Razzle: Razzle y Serverless

Creado en 30 may. 2018  ·  30Comentarios  ·  Fuente: jaredpalmer/razzle

Hola !
Estoy tratando de ejecutar un proyecto razzle (materialUI, Typecript, Apollo & After) sin servidor.
¿Cuál es la mejor manera de manejar esto con Serverless?

Si conoce algún ejemplo, me complace echarle un vistazo. Gracias !

Comentario más útil

Así es como he estado implementando aplicaciones Razzle en AWS Lambda con AWS CDK :

RazzleStack

import * as CDK from '@aws-cdk/core';
import * as S3 from '@aws-cdk/aws-s3';
import * as S3Deployment from '@aws-cdk/aws-s3-deployment';
import * as Lambda from '@aws-cdk/aws-lambda';
import * as APIGateway from '@aws-cdk/aws-apigateway';
import * as SSM from '@aws-cdk/aws-ssm';
import * as SecretsManager from '@aws-cdk/aws-secretsmanager';

import { ConfigProps, getParam, ModeStack } from '../helpers';

export class RazzleStack extends ModeStack {
  constructor(app: CDK.App, id: string, props: ConfigProps) {
    super(app, id, props);

    /**
     * S3 bucket to the /public folder
     */
    const publicBucketName = `my-razzle-app-bucket-public-files-${this.mode}`;
    const bucketPublicFiles = new S3.Bucket(this, publicBucketName, {
      publicReadAccess: true,
      bucketName: publicBucketName.toLowerCase(),
    });

    /**
     * Store S3 bucket name
     */
    new SSM.StringParameter(this, `MyRazzleAppBucketAssetsName${this.Mode}`, {
      description: `My Razzle App S3 Bucket Name for Assets on ${this.Mode}`,
      parameterName: `/${props.name}/S3/Assets/Name`,
      stringValue: bucketPublicFiles.bucketName,
    });

    /**
     * Store S3 domainName name
     */
    new SSM.StringParameter(this, `MyRazzleAppBucketAssetsDomainName${this.Mode}`, {
      description: `My Razzle App S3 Bucket DomainName for Assets on ${this.Mode}`,
      parameterName: `/${props.name}/S3/Assets/DomainName`,
      stringValue: bucketPublicFiles.bucketDomainName,
    });

    /**
     * Deploy public folder of build to `my-razzle-app-bucket-public-files-${this.mode}` bucket
     */
    new S3Deployment.BucketDeployment(this, `${publicBucketName}-deploy`, {
      sources: [S3Deployment.Source.asset('./build/public')],
      destinationBucket: bucketPublicFiles,
    });

    /**
     * Environment Variables for SSR Function
     */
    const environmentKeys = [
      'NODE_ENV',
      'RAZZLE_GRAPHQL_URL',
      'RAZZLE_MAPBOX_ACCESS_TOKEN',
      'RAZZLE_GOOGLE_RECAPTCHA_SITE',
      'RAZZLE_GA_ID',
    ];

    const environmentSecret = SecretsManager.Secret.fromSecretAttributes(
      this,
      `MyRazzleAppEnvironmentSecret${this.Mode}`,
      {
        secretArn: getParam(this, `MyRazzleAppSecretsArn${this.Mode}`),
      },
    );

    let environment: { [key: string]: string } = {};
    for (const key of environmentKeys) {
      environment[key] = environmentSecret.secretValueFromJson(key).toString();
    }

    /**
     * Razzle SSR Function
     */
    const myRazzleAppSsrFunction = new Lambda.Function(this, `MyRazzleAppSSRFunction${this.Mode}`, {
      description: `Lambda Function that runs My Razzle App SSR on ${this.Mode}`,
      code: Lambda.Code.fromAsset('./build', {
        exclude: ['public', 'static', '*.json'],
      }),
      handler: 'server.handler',
      runtime: Lambda.Runtime.NODEJS_12_X,
      memorySize: 512,
      timeout: CDK.Duration.seconds(5),
      environment,
      tracing: Lambda.Tracing.ACTIVE,
    });

    /**
     * Razzle ApiGateway
     */
    const razzleSsrApiGatewayName = `MyRazzleAppSSRApiGateway${this.Mode}`;
    const api = new APIGateway.RestApi(this, razzleSsrApiGatewayName, {
      description: `ApiGateway that exposes My Razzle App SSR on ${this.Mode}`,
      binaryMediaTypes: ['*/*'],
      endpointTypes: [APIGateway.EndpointType.REGIONAL],
      deployOptions: {
        stageName: this.mode,
      },
    });
    const integration = new APIGateway.LambdaIntegration(myRazzleAppSsrFunction);
    const root = api.root;
    const pathApi = api.root.addResource('{proxy+}');

    root.addMethod('GET', integration);
    pathApi.addMethod('ANY', integration);

    /**
     * Razzle ApiGateway ID
     */
    new SSM.StringParameter(this, `MyRazzleAppAPIGatewayRestId${this.Mode}`, {
      description: `My Razzle App ApiGateway ID on ${this.Mode}`,
      parameterName: `/${props.name}/APIGateway/ApiId`,
      stringValue: api.restApiId,
    });
  }
}

Todos 30 comentarios

Alguien acaba de hacer esto y tuiteó al respecto. Sería un ejemplo genial

¡No puedo encontrar el tweet! Lo tienes ?

¿Fue mi tweet? Acabo de reemplazar index.js (donde ocurre toda la carga en caliente) con

import awsServerlessExpress from 'aws-serverless-express'
import app from './server'
const binaryMimeTypes = [
  'application/octet-stream',
  'font/eot',
  'font/opentype',
  'font/otf',
  'image/jpeg',
  'image/png',
  'image/svg+xml',
]
const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes)

export const handler = (event, context, callback) => {
  awsServerlessExpress.proxy(server, event, context)
}

A continuación, ejecute npm run build , copie node_modules/ en build/ , comprima server.js junto con la carpeta node_modules/ y cárguela en AWS Lambda. Todo en public/ luego se carga a S3 y se envía a través de Cloudfront.

Para Lambda -> infraestructura de puerta de enlace API, utilicé Terraform y seguí esta guía: https://www.terraform.io/docs/providers/aws/guides/serverless-with-aws-lambda-and-api-gateway.html

Sin embargo, todavía no es perfecto: aparece este error en la carga del paquete del lado del cliente (https://static.jobsok.io/):

image


Actualizar:
No te jodo, eliminar node_modules y reinstalar me dio:

File sizes after gzip:

  210.38 KB (+8 B)  build/static/js/bundle.1a960add.js
  1.96 KB           build/static/css/bundle.5865fae5.css

Sin cambios en el código: volvió a funcionar el paquete del lado del cliente

Mi handler.js (o index.js) es el mismo.
Luego, construyo todo con webpack (proyecto + node_modules). (Solo necesita modificar razzle.config.js para eso)

Estoy trabajando sin servidor, no con terraform. Básicamente lo mismo. Solo necesita importar el paquete relativo para el controlador (por alguna razón, el paquete web no empaqueta este, tal vez porque está en un archivo / ruta diferente, lo arreglará más adelante).

Carga todo esto sin servidor, y eso es todo. Puedes ver el proyecto aquí: https://github.com/CuistotduCoin/cuistot

Está lejos de ser perfecto y limpio.

Por cierto, @jaredpalmer , ¿puedes ayudarme con la configuración de razzle / webpack?
Quiero incluir todo lo necesario en el paquete (node_modules incluidos) con el mejor rendimiento. ¿Algún ejemplo / consejo? (Con la configuración de TypeScript)

@ Frozenmd ¿puedes compartir tu razzle.config?

@romainquellec el mío está vacío, no hay configuración adicional más allá de lo que proporciona razzle

Bueno, no sé por qué, pero no puedo acceder a aws-serverless-express definido en dependencias (tal vez más).
Y para optimizar todo eso, quiero excluir aws-sdk de la compilación final (siempre está disponible en una función lambda, aunque lo veré más adelante)

Creo que proviene de fuentes externas, pero no puedo entenderlo.

Sí, tuve el mismo problema. Mi única solución fue cerrar el archivo server.js con todos los node_modules

No puedo en lambda. El tamaño límite oficial es de 50 meses.
Pregunta general para todos: Cómo agrupar node_modules con buen rendimiento con razzle. Gracias !

No usamos lambda, pero agrupamos todos nuestros node_modules eliminando la opción externa predeterminada en razzle.config.js. Esto es genial porque significa que la carpeta de compilación es efectivamente un artefacto de compilación. Luego lo colocamos en s3, luego nuestra tarea de Jenkins extrae la nueva carpeta en cada servidor y reinicia pm2.

@jaredpalmer : ¿hay alguna posibilidad de que puedas publicar un resumen con ese razzle.config.js ?

eliminando la opción externa predeterminada en razzle.config.js:

Como eso ?
modify(config, { target, dev }) { if (target === 'node' && !dev) { config.externals = []; } return config; }

@romainquellec eso funciona !!

module.exports = {
  modify: (config, { target, dev }, webpack) => {
    // do something to config
    const appConfig = config // stay immutable here

    if (target === 'node' && !dev) {
      appConfig.externals = []
    }

    return appConfig
  },
}

Esta funcionando. Bien ! 👍 👍
¡Es justo agregar un ejemplo! Lo veré este fin de semana. ¿Te importaría participar @ Frozenmd ?

Desafortunadamente, no tendré tiempo libre este fin de semana @romainquellec pero feliz de revisar / colaborar en relaciones públicas

Estoy cerrando esto. Enviará un PR lo antes posible.

@romainquellec , ¿alguna vez hiciste esa solicitud de extracción? ¿Sigue ejecutando su proyecto Razzle en un entorno sin servidor? Recién estoy comenzando a explorar esta posibilidad y me encontré con este hilo :)

@mbrochh No vi una solicitud de extracción al final, pero sigo usando Razzle en https://onlineornot.com para toda mi representación del lado del servidor sin servidor.

También encontré esta publicación de blog: https://medium.com/@RozenMD/build -your-own-app-with-react-graphql-and-serverless-architecture-part-1-server-side-rendering-f0d0144ff5f

Supongo que tendré que sumergirme de cabeza e intentar seguir esa publicación :)

¡Gracias por la publicacion!

https ://max

¡y gracias! :sonrisa:

¿Alguien implementó Razzle en AWS lambda?

También estoy buscando un ejemplo de Razzle en AWS lambda. Si alguien lo ha hecho y está feliz de compartir con nosotros, se lo agradecería mucho.

Así es como he estado implementando aplicaciones Razzle en AWS Lambda con AWS CDK :

RazzleStack

import * as CDK from '@aws-cdk/core';
import * as S3 from '@aws-cdk/aws-s3';
import * as S3Deployment from '@aws-cdk/aws-s3-deployment';
import * as Lambda from '@aws-cdk/aws-lambda';
import * as APIGateway from '@aws-cdk/aws-apigateway';
import * as SSM from '@aws-cdk/aws-ssm';
import * as SecretsManager from '@aws-cdk/aws-secretsmanager';

import { ConfigProps, getParam, ModeStack } from '../helpers';

export class RazzleStack extends ModeStack {
  constructor(app: CDK.App, id: string, props: ConfigProps) {
    super(app, id, props);

    /**
     * S3 bucket to the /public folder
     */
    const publicBucketName = `my-razzle-app-bucket-public-files-${this.mode}`;
    const bucketPublicFiles = new S3.Bucket(this, publicBucketName, {
      publicReadAccess: true,
      bucketName: publicBucketName.toLowerCase(),
    });

    /**
     * Store S3 bucket name
     */
    new SSM.StringParameter(this, `MyRazzleAppBucketAssetsName${this.Mode}`, {
      description: `My Razzle App S3 Bucket Name for Assets on ${this.Mode}`,
      parameterName: `/${props.name}/S3/Assets/Name`,
      stringValue: bucketPublicFiles.bucketName,
    });

    /**
     * Store S3 domainName name
     */
    new SSM.StringParameter(this, `MyRazzleAppBucketAssetsDomainName${this.Mode}`, {
      description: `My Razzle App S3 Bucket DomainName for Assets on ${this.Mode}`,
      parameterName: `/${props.name}/S3/Assets/DomainName`,
      stringValue: bucketPublicFiles.bucketDomainName,
    });

    /**
     * Deploy public folder of build to `my-razzle-app-bucket-public-files-${this.mode}` bucket
     */
    new S3Deployment.BucketDeployment(this, `${publicBucketName}-deploy`, {
      sources: [S3Deployment.Source.asset('./build/public')],
      destinationBucket: bucketPublicFiles,
    });

    /**
     * Environment Variables for SSR Function
     */
    const environmentKeys = [
      'NODE_ENV',
      'RAZZLE_GRAPHQL_URL',
      'RAZZLE_MAPBOX_ACCESS_TOKEN',
      'RAZZLE_GOOGLE_RECAPTCHA_SITE',
      'RAZZLE_GA_ID',
    ];

    const environmentSecret = SecretsManager.Secret.fromSecretAttributes(
      this,
      `MyRazzleAppEnvironmentSecret${this.Mode}`,
      {
        secretArn: getParam(this, `MyRazzleAppSecretsArn${this.Mode}`),
      },
    );

    let environment: { [key: string]: string } = {};
    for (const key of environmentKeys) {
      environment[key] = environmentSecret.secretValueFromJson(key).toString();
    }

    /**
     * Razzle SSR Function
     */
    const myRazzleAppSsrFunction = new Lambda.Function(this, `MyRazzleAppSSRFunction${this.Mode}`, {
      description: `Lambda Function that runs My Razzle App SSR on ${this.Mode}`,
      code: Lambda.Code.fromAsset('./build', {
        exclude: ['public', 'static', '*.json'],
      }),
      handler: 'server.handler',
      runtime: Lambda.Runtime.NODEJS_12_X,
      memorySize: 512,
      timeout: CDK.Duration.seconds(5),
      environment,
      tracing: Lambda.Tracing.ACTIVE,
    });

    /**
     * Razzle ApiGateway
     */
    const razzleSsrApiGatewayName = `MyRazzleAppSSRApiGateway${this.Mode}`;
    const api = new APIGateway.RestApi(this, razzleSsrApiGatewayName, {
      description: `ApiGateway that exposes My Razzle App SSR on ${this.Mode}`,
      binaryMediaTypes: ['*/*'],
      endpointTypes: [APIGateway.EndpointType.REGIONAL],
      deployOptions: {
        stageName: this.mode,
      },
    });
    const integration = new APIGateway.LambdaIntegration(myRazzleAppSsrFunction);
    const root = api.root;
    const pathApi = api.root.addResource('{proxy+}');

    root.addMethod('GET', integration);
    pathApi.addMethod('ANY', integration);

    /**
     * Razzle ApiGateway ID
     */
    new SSM.StringParameter(this, `MyRazzleAppAPIGatewayRestId${this.Mode}`, {
      description: `My Razzle App ApiGateway ID on ${this.Mode}`,
      parameterName: `/${props.name}/APIGateway/ApiId`,
      stringValue: api.restApiId,
    });
  }
}

@jgcmarins sobre esa configuración de alboroto. ¿Podrías hacer un paso a paso sobre cómo usar esto? Me gustaría agregarlo a razzle docs.

https://razzle-git-canary.jared.vercel.app/deployment-options/aws

Necesito ayuda con esto, ¿alguien puede echarme una mano?

@fivethreeo, el paso a paso sería configurar CDK en una cuenta de AWS y luego ejecutar cdk deploy con algunos indicadores adicionales y ya está \ o /

Me gustaría hacer el escenario con un dominio en lugar de una ruta. Tal vez haga un ejemplo completo con rds, rotación de claves, TypeOrm, typegraphql, Formik y jwt, pero no como ejemplo en razzle en sí.

De lo contrario, no falta nada.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

alexjoyner picture alexjoyner  ·  3Comentarios

knipferrc picture knipferrc  ·  5Comentarios

charlie632 picture charlie632  ·  4Comentarios

dizzyn picture dizzyn  ·  3Comentarios

panbanda picture panbanda  ·  5Comentarios