Razzle: exponer una lista de todos los activos que son seguros para establecer inmutable `Cache-Control`

Creado en 31 jul. 2020  ·  40Comentarios  ·  Fuente: jaredpalmer/razzle

🚀 Solicitud de funciones

He estado investigando la mejor manera de agregar un middleware a mi servidor razzle para detectar cada vez que sirve un archivo creado por razzle que incluye un paquete web [hash:8] o [contenthash:8] en el nombre del archivo. Primero discutí algunos de los problemas con los que me estoy encontrando aquí https://github.com/jaredpalmer/razzle/pull/1368#issuecomment -664015050

Me gustaría que Razzle genere y exponga la lista de archivos / activos seguros para ser considerados "inmutables" (con el propósito de establecer Cache-Control encabezados en las respuestas) de una manera que sea fácil de consumir sin una transformación adicional del archivos chunks.json y / o assets.json

NOTA: al configurar respuestas de control de caché inmutables y de larga duración, quiero evitar hacer cualquier tipo de "aproximación" sobre si un archivo puede considerarse inmutable (también conocido como regex para detectar un hash en el nombre del archivo) porque un falso positivo puede conducir a un archivo que se almacena en caché de forma inmutable durante mucho tiempo y no podría solucionarse mediante una invalidación de la caché del lado del servidor, lo que puede ser un problema muy doloroso de solucionar.

Comportamiento actual

TL; DR de por qué es difícil intentar usar los archivos json actualmente expuestos:

  • Para obtener la lista concreta de todos los archivos que son seguros para almacenar en caché de manera inmutable (porque tienen hashes de compilación o contenido), necesito usar chunks.json y assets.json . chunks.json incluye archivos sourcemap y assets.json tiene archivos como png / fonts, etc. que chunks.json no tiene.
  • Los assets.json y chunks.json no están en el mismo formato (este es posiblemente un problema que se manifiesta para mí porque dejo que el paquete web divida las cosas en varios fragmentos), por lo que se requieren diferentes transformaciones ad-hoc para recopilar la lista completa de todos los archivos /activos. Algunas de las diferencias son:

    • Parece que para cualquier fragmento que no esté en (assets.json).client (por ejemplo: "client": { "js": "/static/js/bundle.6fc534aa.js" } ), assets.json agrupe todos los demás activos bajo una cadena vacía (por ejemplo: "": { "js": "/static/js/0.cb47cee9.chunk.js" } ).

    • si solo hay un archivo presente en un grupo chunks.json, será una matriz con un elemento en él (por ejemplo: "client": { "css": ["filename.css"] } ), si solo hay un archivo de archivo presente en assets.json, en su lugar será solo el una sola cadena (por ejemplo: "client": { "css": "filename.css" } ).

  • Mi assets.json contiene actualmente "json": "/../chunks.json" que no es algo que creo que debería estar allí (no estoy seguro si esto es un error o no) pero tengo que eliminarlo manualmente al hacer la lista de archivos que pueden recibir encabezados de respuesta de control de caché de larga duración.
  • El plan para agregar una matriz chunks: ["1", "2", "3"] a chunks.json es algo molesto porque significa que tengo que hacer un trabajo adicional para filtrar el (chunks.json).client.chunks porque no contiene una matriz de archivos como (chunks.json).client.css y (chunks.json).client.js etc.
  • Antes del cambio que hice aquí, los archivos que no estaban en el fragmento client ni siquiera aparecían en el archivo chunks.json . Hice / sugerí el cambio para cambiarlo y usar el (los) número (s) de fragmento como clave porque al menos aparecen en el archivo. La desventaja de esto es que ahora chunks.json y assets.json más diversos en su esquema cuando se trata de fragmentos que no son el fragmento principal con nombre ( "client": {/* blah */ } ).

usando assets.json y chunks.json

Actualmente usando assets.json y chunks.json, esto es lo que he tenido que hacer aproximadamente hasta ahora

No tengo:

  • agregado cargando el assets.json todavía y resolviendo diferencias entre los formatos
  • Filtrar archivos / campos en el json que sé que no están destinados a estar allí, como "chunks": ["1", "2", "3"] y "json": "/../chunks.json"
function razzleCacheableFiles() {
  // TODO: Add loading the assets.json file to support (png/txt files etc)

  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const chunks = require(process.env.RAZZLE_CHUNKS_MANIFEST!);
  const filesByType = Object.entries(chunks).reduce(
    (chunkAcc: any, [, chunk]) => {
      const types = Object.entries(chunk as any).reduce(
        (typeAcc, [fileType, files]) => {
          return {
            [fileType]: chunkAcc[fileType]
              ? [...chunkAcc[fileType], ...(files as string[])]
              : files,
          };
        },
        {},
      );
      return types;
    },
    {},
  );
  const files = Object.entries(filesByType).reduce(
    (acc: any[], [, files]) => [...acc, ...(files as string[])],
    [],
  );
  return files;
}

const cacheableFiles = razzleCacheableFiles();

// Serve static files located under `process.env.RAZZLE_PUBLIC_DIR`
const assetCaching = {
  immutable: {
    maxAge: CacheFor.OneMonth,
    sMaxAge: CacheFor.OneYear,
  },
  default: {
    maxAge: CacheFor.OneDay,
    sMaxAge: CacheFor.OneWeek,
  }
};
app.use(
  serve(process.env.RAZZLE_PUBLIC_DIR!, {
    setHeaders(res, path) {
      const filename = path.replace(process.env.RAZZLE_PUBLIC_DIR!, "");
      const hasHashInFilename = cacheableFiles.includes(filename);
      if (hasHashInFilename) {
        const { immutable } = assetCaching;
        res.setHeader(
          "Cache-Control",
          `max-age=${immutable.maxAge},s-maxage=${immutable.sMaxAge},immutable`,
        );
        return;
      }
      res.setHeader(
        "Cache-Control",
        `max-age=${assetCaching.default.maxAge},s-maxage=${asetCaching.default.sMaxAge}`,
      );
    },
  }),
);

Una descripción clara y concisa de cuál es el comportamiento / uso actual.

Comportamiento deseado

Probablemente haya muchas formas de hacer esto, pero lo principal que quiero es solo una forma de cargar una matriz de todos los activos en caché / inmutables generados por la compilación de razzle. el resultado podría verse así:

// File: caching.json
// contains all files/assets with a hash in them regardless of what type of file they are.
{
  "immutable": [
    "/static/js/0.cb47cee9.chunk.js",
    "/static/js/0.cb47cee9.chunk.js.map",
    "/static/js/0.cb47cee9.chunk.js.LICENSE.txt",
    "/static/media/ferris-error.407b714e.png"
  ],
  // I'm not even sure if this is required because I don't think razzle generates any files that don't have hashes in them?
  // possibly files copied in from the `public/` directory during build. but I'm not even sure if it'd that'd useful
  "standard": []
}
// RAZZLE_CACHING_MANIFEST is probably a silly name but 
const cacheableFiles = require(process.env.RAZZLE_CACHING_MANIFEST!);

// Serve static files located under `process.env.RAZZLE_PUBLIC_DIR`
const assetCaching = {
  immutable: {
    maxAge: CacheFor.OneMonth,
    sMaxAge: CacheFor.OneYear,
  },
  default: {
    maxAge: CacheFor.OneDay,
    sMaxAge: CacheFor.OneWeek,
  }
};
app.use(
  serve(process.env.RAZZLE_PUBLIC_DIR!, {
    setHeaders(res, path) {
      const filename = path.replace(process.env.RAZZLE_PUBLIC_DIR!, "");
      const hasHashInFilename = cacheableFiles.immutable.includes(filename);
      if (hasHashInFilename) {
        const { immutable } = assetCaching;
        res.setHeader(
          "Cache-Control",
          `max-age=${immutable.maxAge},s-maxage=${immutable.sMaxAge},immutable`,
        );
        return;
      }
      res.setHeader(
        "Cache-Control",
        `max-age=${assetCaching.default.maxAge},s-maxage=${asetCaching.default.sMaxAge}`,
      );
    },
  }),
);

Solución sugerida

No he investigado completamente cuál sería una buena solución, pero después de intentar armar esta lista de "activos almacenables en caché" en tiempo de ejecución usando assets.json y chunks.json , estoy bastante convencido de que en un Como mínimo, la mejor manera de lograr esto sería en el momento de la compilación con algún tipo de complemento de paquete web y evitar las inconsistencias de esos dos archivos.

Para mis propósitos, probablemente comenzaré inicialmente a buscar cómo lograr esto con un complemento en lugar de en tiempo de ejecución como lo he estado haciendo, pero creo que sería de gran valor tener esto integrado para razzle de forma predeterminada. Ser capaz de establecer un control de caché de larga duración en archivos con hash es en gran parte la razón por la que se obtienen con hash para empezar, por lo que parece apropiado exponer una lista de todos esos archivos.

¿A quién impacta esto? ¿Para quien es esto?

Cualquier usuario que desee establecer encabezados de respuesta de control de caché inmutables y de larga duración adecuados para los archivos generados y hash por razzle.

Describe las alternativas que has considerado

  • Genere una lista de todos los archivos inmutables / almacenables en caché en tiempo de ejecución al juntar chunks.json y assets.json (parece propenso a errores y frágil).
  • Cree un complemento externo para generar previamente una lista de archivos que se pueden almacenar en caché en el momento de la compilación. (parece posiblemente frágil en las versiones razzle para una característica que parece que debería estar integrada / estable)
  • Agréguelo como un complemento interno a la configuración predeterminada de Razzle y exponga una forma de acceder a él de forma predeterminada, por ejemplo: require(process.env.RAZZLE_CACHING_MANIFEST!) . ()

Contexto adicional

Estaría dispuesto a ayudar / contribuir para hacer este cambio, pero podría necesitar un poco de un punto en la dirección correcta (y por supuesto si este es un cambio que sería aceptado / bienvenido).

También un pensamiento, tener algo como esto podría facilitar tener algunas pruebas / estabilidad para asegurarse de que las cosas estén usando [contenthash:8] lugar de [hash:8] (construir hash) si / cuando pueden https: / /github.com/jaredpalmer/razzle/issues/1331

discussion enhancement help wanted razzle webpack webpack-config

Comentario más útil

Hizo un lanzamiento canario ahora :)

Todos 40 comentarios

Parece una idea que vale la pena.

También está conectado a otro problema que es la configuración de chunkGroup en optimización. Porque si eso estuviera configurado, la cadena vacía sería "compartida", "marco", etc.

Si miras next.js, usan una configuración de chunkGroups como esta.

Cuando cambiemos esto, también será incompatible con versiones anteriores, pero debe hacerse. Tengo algunos cambios más importantes que también necesitan un lanzamiento importante.

Pero siéntete libre de crear un código que resuelva esto 😀

Si miras next.js, usan una configuración de chunkGroups como esta.

Oh, genial, no sé si / cómo otras herramientas / marcos se acercan a esto, ¿tienes un enlace / ejemplos?

También está conectado a otro problema que es la configuración de chunkGroup en optimización

¿Un problema de razzle abierto? ¿Podrías señalarme cuál para que pueda tener más contexto?

Creo que una forma potencial de resolver esto es definir con más fuerza la forma / esquema de los chunks.json y assets.json . Probablemente debería ser considerado cuidadosamente (y tener un aumento de versión principal) pero si hay ejemplos de cómo otros marcos, etc.han resuelto el problema, podría tener sentido seguir una dirección similar

1361 # 1370

Y

https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack-config.ts#L378

No estoy seguro de cómo hacen el manifiesto.

Eche un vistazo a https://github.com/jaredpalmer/razzle/issues/1377 ahora, se agregó un nuevo ejemplo :)

@fivethreeo No he podido dedicar más tiempo a este tema específicamente 😅, definitivamente intentaré pasar algo de tiempo probando la versión 4. Si cree que está listo, espero intentar probarlo en los próximos días.

No estoy seguro de si es de mucho interés, pero he hecho público lo que estoy trabajando ahora aquí .

Estoy bastante interesado en la versión 4 porque espero que signifique que puedo eliminar tantas modificaciones de "complementos" que tenga que configurar aquí , especialmente para el mecanografiado.

El tema de los activos almacenables en caché está aquí .

Todos los archivos usan contenthash ahora. Los archivos copiados diría que es una mala práctica cuando tenemos un paquete.

No estoy seguro de entender lo que quiere decir con "Los archivos copiados, diría que es una mala práctica cuando tenemos un paquete".

Actualmente, el comportamiento es que si coloca algún archivo en la carpeta de nivel superior public/ en su proyecto razzle.

build/
public/
  robots.txt
  manifest.json
package.json

Se adaptan a los activos estáticos cuando razzle build

build/
  public/
    robots.txt
    manifest.json
    static/
      ...
public/
  robots.txt
  manifest.json
package.json

Estaba pensando que sería conveniente mantener una lista de todos los activos que se copiaron durante la compilación para que sean específicamente aptos para el destino por separado para aplicar el control de caché.

Creo que el argumento en contra (en el que puedo pensar) sería que podría no ser necesario que el usuario distinga entre los archivos que razzle ha copiado durante la compilación y los que podrían haberse colocado manualmente allí fuera de razzle build

Creo que public solo debe contener robots.txt y favicon.ico y no serán versionados por hashes.

Todo lo demás debería estar incluido en webpack. Se deben agrupar los favicons más grandes.

Tal vez, pero incluso si desea mantener la compatibilidad "plug and play" con un create-react-app predeterminado, podría valer la pena considerar que el manifiesto de la aplicación y algunos iconos también estarán presentes allí .

Recuerdo vagamente que hay razones por las que manifest.json / manifest.webmanifest no debería contener un hash de compilación, que es una de las razones por las que a menudo se excluye del procesamiento por parte del paquete. Puede que me equivoque o no lo recuerde, pero posiblemente tenga algo que ver con las PWA y el modo fuera de línea

¿Alguno de los proyectos de ejemplo de razzle implementa el soporte de PWA (y / o trabajador de servicio)?

Quizás menos relevante, pero algunas otras cosas que puse en la carpeta public/ en el pasado al usar create-react-app son archivos descargables relacionados con el sitio web, pero donde se requieren URL persistentes. Como tener un documento pdf al que se puede vincular al enviar correos electrónicos, etc. 🤷

Intentando buscar ejemplos de si / por qué / cuándo los webmanifests deberían estar separados del empaquetado:

https://stackoverflow.com/questions/54145027/what-happens-when-you-add-a-version-hash-to-your-service-worker-file

Hay un comentario en esa publicación que enlaza con https://github.com/w3c/manifest/issues/446#issuecomment -351368893

Sí, los archivos descargables deberían ir allí. Hm, pero ¿cómo agregamos esos archivos a assets.json? ¿Algunas ideas? 😀 ¿Deberíamos hacer que el paquete web los encuentre y los agrupe como están? Modificar assets.json parece un truco.

No creo que haya un ejemplo de PWA. Pero si necesitan un nombre coherente. Eso debe ser manejado por webpack.

Reemplazaré el complemento de activos con el complemento de manifiesto para que podamos adaptar la salida.

Se agregó un nuevo manifiesto de activos con todos los archivos https://github.com/jaredpalmer/razzle/commit/1c6e9169e9d8eee256d0f118f8a88da8de85989f ¿ Alguna sugerencia sobre mejoras?

Hizo un lanzamiento canario ahora :)

Veo que el complemento de manifiesto no se mantiene realmente. Lo mejor sería hacer las nuestras. Pero actualmente no conozco a nadie más que a mí oa la gente del paquete web que pueda hacer eso.

Agregado a la rama canary ahora. Una especie de truco por ahora. Pero funciona y es un comienzo que se puede mejorar.

Después de considerarlo un poco, no agregaré esto al núcleo.

Pero aquí está el código que se me ocurrió:

        new ManifestPlugin({
          fileName: path.join(paths.appBuild, 'assets.json'),
          writeToFileEmit: true,
          generate: (seed, files) => {
            const entrypoints = new Set();
            const noChunkFiles = new Set();
            const longTermCacheFiles = new Set();
            files.forEach(file => {
              if (file.isChunk) {
                const groups = (
                  (file.chunk || {})._groups || []
                ).forEach(group => entrypoints.add(group));
              } else {
                noChunkFiles.add(file);
              }
              if (!webpackOptions.fileLoaderExclude.some(re=>re.test(file.path))) {
                let fileHasHash = /\[(build|content)?hash/.test(
                  typeof webpackOptions.fileLoaderOutputName == 'function' ?
                  webpackOptions.fileLoaderOutputName(file) : webpackOptions.fileLoaderOutputName);
                if (fileHasHash) longTermCacheFiles.add(file);
              } else if (webpackOptions.urlLoaderTest.some(re=>re.test(file.path))) {
                let urlHasHash = /\[(build|content)?hash/.test(
                  typeof webpackOptions.urlLoaderOutputName == 'function' ?
                  webpackOptions.urlLoaderOutputName(file) : webpackOptions.urlLoaderOutputName);
                if (urlHasHash) longTermCacheFiles.add(file);
              } else if (webpackOptions.cssTest.some(re=>re.test(file.path))) {
                let cssHasHash = /\[(build|content)?hash/.test(
                  typeof webpackOptions.cssOutputFilename == 'function' ?
                  webpackOptions.cssOutputFilename(file) : webpackOptions.cssOutputFilename);
                if (cssHasHash) longTermCacheFiles.add(file);
              } else if (webpackOptions.jsTest.some(re=>re.test(file.path))) {
                let jsHasHash = /\[(build|content)?hash/.test(
                  typeof webpackOptions.jsOutputFilename == 'function' ?
                  webpackOptions.jsOutputFilename(file) : webpackOptions.jsOutputFilename);
                if (jsHasHash) longTermCacheFiles.add(file);
              }
            });
            const entries = [...entrypoints];
            const entryArrayManifest = entries.reduce((acc, entry) => {
              const name =
                (entry.options || {}).name ||
                (entry.runtimeChunk || {}).name ||
                entry.id;
              const allFiles = []
                .concat(
                  ...(entry.chunks || []).map(chunk =>
                    chunk.files.map(path => config.output.publicPath + path)
                  )
                )
                .filter(Boolean);

              const filesByType = allFiles.reduce((types, file) => {
                const fileType = file.slice(file.lastIndexOf('.') + 1);
                types[fileType] = types[fileType] || [];
                types[fileType].push(file);
                return types;
              }, {});

              const chunkIds = [].concat(
                ...(entry.chunks || []).map(chunk => chunk.ids)
              );

              return name
                ? {
                    ...acc,
                    [name]:  { ...filesByType, chunks: chunkIds },
                  }
                : acc;
            }, seed);
            entryArrayManifest['noentry'] = [...noChunkFiles]
              .map(file => file.path)
              .reduce((types, file) => {
                const fileType = file.slice(file.lastIndexOf('.') + 1);
                types[fileType] = types[fileType] || [];
                types[fileType].push(file);
                return types;
              }, {});
              entryArrayManifest['cacheable'] = [...longTermCacheFiles]
                .map(file => file.path);
            return entryArrayManifest;
          },
        })

Pero aprendí mucho sobre activos;)

Lo siento, no he podido pasar mucho tiempo con esto en un tiempo, pero se ve bien. Echando un vistazo ahora a actualizar mis cosas a la última versión estable de razzle y probar su sugerencia como un complemento personalizado.

Se ve bastante bien, pero estoy un poco confundido acerca de esto:

let fileHasHash = /\[(build|content)?hash/.test(
  typeof webpackOptions.fileLoaderOutputName == 'function'
    ? webpackOptions.fileLoaderOutputName(file)
    : webpackOptions.fileLoaderOutputName);

if (fileHasHash) longTermCacheFiles.add(file);

¿Qué se supone que sea webpackOptions.fileLoaderOutputName ? para mí siempre parece indefinido.

Solo en razzle canary

Aseado, he hecho algunos progresos ahora con la obtención de una rama en mi trabajo de proyecto en la rama canario. No funciona del todo, en este momento mis problemas parecen tener que ver principalmente con la configuración del cargador de babel para reconocer paquetes hermanos. Puedo compilar pero luego obtengo problemas de "no puedo encontrar el módulo" cuando intento ejecutarlo.

Esto probablemente no sea demasiado interesante / útil, pero:

https://github.com/bootleg-rust/sites/pull/2/files

de la memoria originalmente tomé prestada la configuración de https://github.com/jaredpalmer/razzle/issues/664

/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime sync:2
        var e = new Error("Cannot find module '" + req + "'");
         ^
Error: Cannot find module 'undefined'
    at require (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime sync:2:10)
    at razzleCacheableFiles (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime/server.tsx:106:18)
    at createKoaApp (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime/server.tsx:61:26)
    at Module.call (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/src/server.tsx:42:13)
    at a (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:19:22)
    at Object.call (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/server.js:1:31123)
    at __webpack_require__ (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:19:22)
    at /Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:83:10
    at Object.<anonymous> (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/server.js:1:935)

https://github.com/jaredpalmer/razzle/issues/1459

y establezca NODE_PATH = .. / o algo

Ok, profundizando un poco en él, me acabo de dar cuenta de que el problema en realidad es que process.env.RAZZLE_CHUNKS_MANIFEST no se define 😅.

Lo único para lo que lo estaba usando era para detectar qué activos se podían almacenar en caché, así que parece que debería poder darle la nueva configuración ManifestPlugin que vinculó ahora para reemplazarla 🎉.

¡OK!

Hice un complemento personalizado en mi proyecto que parece funcionar lo suficientemente bien para mi caso de uso por el momento. El código que se le ocurrió fue muy útil teniendo eso como punto de partida.

Lo cambié un poco, pero para su información, creo que hay un problema en el que cree que todo lo procesa file-loader porque usa Array.prototype.every() lugar de Array.prototype.some() : !webpackOptions.fileLoaderExclude.every(re=>re.test(file.path))

En caso de que sea útil compartir aquí:

function modifyWebpackConfig({
  env: { target, dev },
  webpackConfig,
  webpackObject,
  options: { pluginOptions, razzleOptions, webpackOptions },
  paths,
}) {
  // TODO: allow passing in extra file categorizers with `pluginOptions`
  const fileCategorizers = [
    {
      test: webpackOptions.urlLoaderTest,
      outputName: webpackOptions.urlLoaderOutputName,
    },
    {
      test: webpackOptions.cssTest,
      outputName: webpackOptions.cssOutputFilename,
    },
    {
      test: webpackOptions.jsTest,
      outputName: webpackOptions.jsOutputFilename,
    },
    {
      exclude: webpackOptions.fileLoaderExclude,
      outputName: webpackOptions.fileLoaderOutputName,
    },
  ];

  const fileName = path.join(paths.appBuild, "cacheable-assets.json");
  const assetPlugin = new WebpackManifestPlugin({
    fileName,
    writeToFileEmit: true,
    generate: (seed, files) => {
      const notHashedFiles = new Set();
      const hashedFiles = new Set();

      const setFileAs = (file, { containsHash }) => {
        if (containsHash) {
          hashedFiles.add(file);
        } else {
          notHashedFiles.add(file);
        }
      };

      files.forEach((file) => {
        if (file.name.startsWith("..")) {
          // Files that start with ".." will live outside of the public/
          // folder and therefore can't/shouldn't be accessed.
          return;
        }

        const fileCategorized = fileCategorizers.some(
          ({ test, exclude, outputName }) => {
            const passesTest =
              test != null ? fileMatchesAnyRegexp(file, test) : true;

            const passesExclude =
              exclude != null ? !fileMatchesAnyRegexp(file, exclude) : true;

            const fileMatches =
              passesTest &&
              passesExclude &&
              fileMatchesTemplate(file.path, outputName);

            if (fileMatches) {
              const containsHash = webpackLoaderOutputContainsHash(
                outputName,
                file,
              );

              setFileAs(file, { containsHash });
            }

            return fileMatches;
          },
        );

        if (!fileCategorized) {
          // TODO: allow "strict" vs "lazy" mode here where we can only use
          // regex on the filename to guess if a file contains a hash in it.
          setFileAs(file, { containsHash: false });
        }
      });

      const mutable = [...notHashedFiles].map((file) => file.path);
      const immutable = [...hashedFiles].map((file) => file.path);
      return {
        mutable,
        immutable,
      };
    },
  });

  if (target === "web") {
    webpackConfig.plugins.push(assetPlugin);
  }

  if (target === "node") {
    // NOTE: adding multiple DefinePlugin's causes issues
    // so we have to find and edit the existing one.
    const definePlugin = webpackConfig.plugins.find(
      (p) => p.constructor.name === "DefinePlugin",
    );
    definePlugin.definitions[
      "process.env.RAZZLE_PLUGIN_CACHEABLE_ASSETS"
    ] = JSON.stringify(fileName);
  }

  return webpackConfig;
}

const cacheableAssetsPlugin = {
  modifyWebpackConfig,
};

O puede verlo aquí https://github.com/bootleg-rust/sites/pull/2/files#diff -59ee436c0396a1f925f067b7e7cbcdee354003236a279e0a87cf8831c7f587e3

Ah, sí, gracias. Todavía me estoy acostumbrando a los nuevos ganchos de complementos, ¡me gusta 🎉!

Creo que el único problema principal que sigo teniendo y que no he podido resolver es que, por alguna razón, el complemento / cargador scss no funciona cuando se ejecuta en modo de desarrollo usando razzle start pero si hago un razzle build completo, todo parece estar bien.

¿Alguna idea de lo que podría ser? ¿O vale la pena poner esto en un problema de github diferente en alguna parte?

También use modifiedPaths para rutas personalizadas también para que se pueda componer.

¿No funciona cómo?

Puede ser un problema nuevo .. :)

No importa, el cargador sass que no funcionaba no era algo específico con el alboroto. algo que ver con una falta de coincidencia de versión o algo con la versión de react-scripts y / o el libro de cuentos que tenía en un paquete hermano que estaba levantando deps.

Ganchos agregados para manejo de activos, cierre 😀

Veo que agregaste un complemento externo. Todavía necesito arreglar eso para cliente / servidor / sin servidor. ¿Tienes alguna idea para eso en canario? Un poco atascado.

Los ganchos que usas ahora.

Veo que agregaste un complemento externo. Todavía necesito arreglar eso para cliente / servidor / sin servidor. ¿Tienes alguna idea para eso en canario? Un poco atascado.

Definitivamente me pareció muy conveniente (principalmente en el servidor) agrupar por defecto todos los node_modules en build/server.js . Ser capaz de excluir la carpeta node_modules completo de las imágenes de la ventana acoplable de producción me parece muy agradable.

Habiendo dicho eso, no he tenido la necesidad de usar / probar cómo funciona con dependencias nativas / específicas de la plataforma (tengo la sensación de que imagemagick tendría problemas)

Mi proceso de pensamiento general con el complemento "externos" que hice es:

const externalsPluginOptions = {
  // By default the NodeJS process uses the externals function razzle has and relies on `node_modules` to still be available
  // after performing a razzle build. Setting this to `true` would mean that all dependencies attempt to get bundled into
  // the build/ output unless explicitly specified as an external
  resetNodeExternals: false,
  // This probably wouldn't actually be required because the browser runtime
  // doesn't have externals by default (i'm assuming)
  resetWebExternals: true,

  webExternals: [
    // add externals for the web runtime here
  ],
  nodeExternals: [
    // add externals for the node runtime here
  ],
};

Para ser honesto, antes de decidirme por una API de configuración "adecuada" para esto (particularmente si iba a estar en el núcleo de razzle) probablemente tendría que leer los documentos del paquete web por externals con un poco más de profundidad en el diferentes casos de uso para externos 😅.

Por el momento, solo lo estoy usando para restablecer los externos para que estén vacíos, de modo que todo se incluya en una aplicación fácilmente portátil que no se basa en node_modules en tiempo de ejecución.

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