Razzle: Stellen Sie eine Liste aller Assets bereit, die sicher sind, unveränderliche "Cache-Kontrolle" festzulegen

Erstellt am 31. Juli 2020  ·  40Kommentare  ·  Quelle: jaredpalmer/razzle

🚀 Funktionsanforderung

Ich habe nach dem besten Weg gesucht, meinem Razzle-Server eine Middleware hinzuzufügen, um zu erkennen, wann immer eine von Razzle erstellte Datei bereitgestellt wird, deren Dateiname ein Webpack [hash:8] oder [contenthash:8] . Ich habe zuerst einige der Probleme besprochen, auf die ich hier stoße: https://github.com/jaredpalmer/razzle/pull/1368#issuecomment -664015050

Ich möchte, dass Razzle die Liste der Dateien / Assets, die sicher sind, als "unveränderlich" (zum Festlegen von Cache-Control -Header in Antworten) auf eine Weise generiert und verfügbar macht, die ohne zusätzliche Transformation der einfach zu konsumieren ist Dateien chunks.json und / oder assets.json

HINWEIS: Wenn Sie langlebige und unveränderliche Cache-Steuerungsantworten festlegen, möchte ich keine "Annäherung" daran vornehmen, ob eine Datei als unveränderlich angesehen werden kann (AKA-Regex, um einen Hash im Dateinamen zu erkennen), da ein falsches Positiv dazu führen kann Eine Datei wird lange Zeit unveränderlich zwischengespeichert und kann nicht durch eine serverseitige Cache-Ungültigmachung behoben werden. Dies kann ein sehr schmerzhaftes Problem sein.

Aktuelles Verhalten

TL; DR, warum es schwierig ist, die aktuell exponierten JSON-Dateien zu verwenden:

  • Um die konkrete Liste aller Dateien zu erhalten, die sicher unveränderlich zwischengespeichert werden können (weil sie Build- oder Inhalts-Hashes enthalten), muss ich sowohl chunks.json als auch assets.json . chunks.json enthält Sourcemap-Dateien und Assets.json enthält Dateien wie PNG / Fonts usw., die chunks.json nicht enthält.
  • Assets.json und chunks.json haben nicht dasselbe Format (dies ist möglicherweise ein Problem, das sich für mich manifestiert, weil ich das Webpack Dinge auf mehrere Chunks aufteilen lasse). Daher ist eine unterschiedliche Ad-hoc-Transformation erforderlich, um die vollständige Liste aller Dateien zusammenzustellen /Vermögenswerte. Einige der Unterschiede sind:

    • Es scheint, dass für jeden Block, der nicht in (assets.json).client (z. B. "client": { "js": "/static/js/bundle.6fc534aa.js" } ) enthalten ist, assets.json alle anderen Assets unter einer leeren Zeichenfolge gruppiert (z. B. "": { "js": "/static/js/0.cb47cee9.chunk.js" } ).

    • Wenn nur eine Datei in einer chunks.json-Gruppe vorhanden ist, handelt es sich um ein Array mit einem Element darin (z. B. "client": { "css": ["filename.css"] } ). Wenn in assets.json nur eine Dateidatei vorhanden ist, handelt es sich stattdessen nur um die einzelne Zeichenfolge (z. B. "client": { "css": "filename.css" } ).

  • Meine Assets.json enthält derzeit "json": "/../chunks.json" was meiner Meinung nach nicht enthalten sein sollte (ich bin mir nicht sicher, ob dies ein Fehler ist oder nicht), aber ich muss dies manuell entfernen, wenn ich die Liste von mache Dateien, denen langlebige Cache-Control-Antwortheader zugewiesen werden können.
  • Der Plan, der Datei chunks.json ein chunks: ["1", "2", "3"] -Array hinzuzufügen, ist etwas ärgerlich, da ich zusätzliche Arbeit leisten muss, um die (chunks.json).client.chunks herauszufiltern, da sie kein Array von Dateien wie enthält (chunks.json).client.css und (chunks.json).client.js etc.
  • Vor der Änderung, die ich hier vorgenommen habe, client waren, nicht einmal in der Datei chunks.json angezeigt. Ich habe die Änderung vorgenommen / vorgeschlagen, um sie so zu ändern, dass die Blocknummer (n) als Schlüssel verwendet werden, da sie dann zumindest in der Datei angezeigt werden. Der Nachteil davon ist, dass sich jetzt chunks.json und assets.json in ihrem Schema weiter unterscheiden, wenn es um Chunks geht, die nicht der primär benannte Chunk sind ( "client": {/* blah */ } ).

Verwenden von Assets.json und Chunks.json

Derzeit benutze ich die Datei resources.json und chunks.json, was ich bisher ungefähr tun musste

Ich habe nicht:

  • Das Laden der Datei "resources.json" und das Beheben von Unterschieden zwischen den Formaten wurde hinzugefügt
  • Das Herausfiltern von Dateien / Feldern im JSON, von denen ich weiß, dass sie nicht dazu bestimmt sind, wie "chunks": ["1", "2", "3"] und "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}`,
      );
    },
  }),
);

Eine klare und präzise Beschreibung des aktuellen Verhaltens / der aktuellen Verwendung.

Gewünschtes Verhalten

Es gibt wahrscheinlich viele Möglichkeiten, dies zu tun, aber das Wichtigste, was ich möchte, ist nur eine Möglichkeit, ein Array aller zwischengespeicherten / unveränderlichen Assets zu laden, die durch Razzle Build generiert wurden. Das Ergebnis könnte ungefähr so ​​aussehen:

// 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}`,
      );
    },
  }),
);

Vorgeschlagene Lösung

Ich habe nicht vollständig untersucht, was eine gute Lösung wäre, aber nachdem ich versucht habe, diese Liste der "zwischenspeicherbaren Assets" zur Laufzeit mit den assets.json und chunks.json bin ich ziemlich überzeugt, dass bei a Der beste Weg, dies zu erreichen, wäre mindestens die Erstellung mit einer Art Webpack-Plugin und die Umgehung der Inkonsistenzen dieser beiden Dateien.

Für meine Zwecke werde ich wahrscheinlich zunächst untersuchen, wie dies mit einem Plugin und nicht wie bisher zur Laufzeit erreicht werden kann, aber ich denke, es wäre von erheblichem Wert, wenn dieses Back-In standardmäßig zum Blenden gebracht würde. Die Möglichkeit, eine langlebige Cache-Steuerung für gehashte Dateien festzulegen, ist vor allem der Grund, warum sie zunächst gehasht werden. Daher erscheint es angemessen, eine Liste all dieser Dateien verfügbar zu machen.

Wer wirkt sich darauf aus? Für wen ist das?

Alle Benutzer, die geeignete langlebige und unveränderliche Cache-Control-Antwortheader für Dateien festlegen möchten, die von razzle generiert und gehasht wurden.

Beschreiben Sie Alternativen, die Sie in Betracht gezogen haben

  • Generieren Sie zur Laufzeit eine Liste aller unveränderlichen / zwischenspeicherbaren Dateien, indem Sie chunks.json und assets.json (scheint fehleranfällig und fragil zu sein).
  • Erstellen Sie ein externes Plugin, um eine Liste der zwischengespeicherten Dateien zur Erstellungszeit vorab zu generieren. (scheint in allen Razzle-Versionen für eine Funktion, die anscheinend eingebrannt / stabil sein sollte, möglicherweise zerbrechlich zu sein)
  • Fügen Sie es als internes Plugin zur Standardkonfiguration von razzle hinzu und legen Sie eine Möglichkeit offen, standardmäßig darauf zuzugreifen, z. B.: require(process.env.RAZZLE_CACHING_MANIFEST!) . ()

Zusätzlicher Kontext

Ich wäre bereit zu helfen / dazu beizutragen, diese Änderung vorzunehmen, aber ich brauche möglicherweise einen Punkt in die richtige Richtung (und natürlich, ob dies eine Änderung ist, die akzeptiert / begrüßt wird oder nicht).

Auch ein Gedanke, so etwas zu haben, könnte es einfacher machen, einige Tests / Stabilität zu haben, um sicherzustellen, dass die Dinge [contenthash:8] anstelle von [hash:8] (Build-Hash) verwenden, wenn / wann sie https: / können. /github.com/jaredpalmer/razzle/issues/1331

discussion enhancement help wanted razzle webpack webpack-config

Hilfreichster Kommentar

Habe jetzt eine kanarische Veröffentlichung gemacht :)

Alle 40 Kommentare

Dies scheint eine lohnende Idee zu sein.

Es ist auch mit einem anderen Problem verbunden, nämlich der Konfiguration der ChunkGroup bei der Optimierung. Denn wenn das eingerichtet wäre, wäre die leere Zeichenfolge "geteilt", "Framework" usw.

Wenn Sie sich next.js ansehen, verwenden sie eine solche chunkGroups-Konfiguration.

Wenn wir dies ändern, wird es auch abwärtskompatibel sein, aber es muss getan werden. Ich habe noch einige große Änderungen im Gange, die auch eine größere Veröffentlichung erfordern.

Sie können sich aber gerne einen Code einfallen lassen, der dieses Problem löst 😀

Wenn Sie sich next.js ansehen, verwenden sie eine solche chunkGroups-Konfiguration.

Oh cool, ich bin mir nicht sicher, ob / wie andere Tools / Frameworks dies angehen. Haben Sie einen Link / Beispiele?

Es ist auch mit einem anderen Problem verbunden, nämlich der Konfiguration der ChunkGroup bei der Optimierung

Ein offenes Razzle-Thema? Könntest du mir zeigen, auf welche, damit ich mehr Kontext bekomme?

Ich denke, dass eine Möglichkeit, dies zu lösen, darin besteht, die Form / das Schema der vorhandenen chunks.json und assets.json stärker zu definieren. Müsste wahrscheinlich sorgfältig überlegt werden (und eine größere Version haben), aber wenn es Beispiele dafür gibt, wie andere Frameworks usw. das Problem gelöst haben, ist es möglicherweise sinnvoll, einer ähnlichen Richtung zu folgen

1361 # 1370

Und

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

Ich bin mir nicht sicher, wie sie das Manifest machen.

Schauen Sie sich jetzt https://github.com/jaredpalmer/razzle/issues/1377 an und fügen Sie ein neues Beispiel hinzu :)

@fivethreeo Ich habe es nicht geschafft, mehr Zeit speziell mit diesem Thema zu verbringen. Ich werde auf jeden Fall versuchen, etwas Zeit damit zu verbringen, die v4-Vorabversion auszuprobieren. Wenn Sie denken, dass es dafür bereit ist, werde ich es hoffentlich in den nächsten Tagen ausprobieren.

Ich bin mir nicht sicher, ob es von großem Interesse ist, aber ich habe das, woran ich gerade arbeite, hier öffentlich gemacht.

Ich bin gespannt , hübsch für v4 , weil es hoffentlich bedeutet , dass ich so viele der „Plug -in “ Überschreibungen entfernen kann ich Set Dinge hier , vor allem für Typoskript.

Das zwischenspeicherbare Asset-Zeug ist hier .

Alle Dateien verwenden jetzt Contenthash. Die kopierten Dateien, die ich sagen würde, sind eine schlechte Praxis, wenn wir einen Bundler haben.

Ich bin mir nicht sicher, ob ich verstehe, was Sie unter "Die kopierten Dateien, die ich sagen würde, sind eine schlechte Praxis, wenn wir einen Bundler haben" verstehen.

Derzeit ist das Verhalten so, dass, wenn Sie Dateien in den Ordner public/ der obersten Ebene in Ihrem Razzle-Projekt legen.

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

Sie werden in die statischen Assets kopiert, wenn Sie razzle build

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

Ich dachte, es wäre wünschenswert, eine Liste aller Assets zu führen, die während des Builds kopiert wurden, damit sie speziell für die Anwendung der Cache-Steuerung separat ausgerichtet werden können.

Ich denke, das Argument dagegen (das ich mir vorstellen kann) wäre, dass der Benutzer möglicherweise nicht zwischen Dateien unterscheiden muss, die Razzle während des Builds kopiert hat, und solchen, die möglicherweise manuell außerhalb von razzle build eingefügt wurden

Ich denke, public sollte nur robots.txt und favicon.ico enthalten und sie werden nicht durch Hashes versioniert.

Alles andere sollte per Webpack gebündelt werden. Alle größeren Favoriten sollten gebündelt werden.

Vielleicht, aber selbst wenn Sie die "Plug and Play" -Kompatibilität mit einem Standardwert von create-react-app beibehalten möchten, sollten Sie berücksichtigen, dass das App-Manifest und einige Symbole auch dort vorhanden sind .

Ich erinnere mich sehr gut daran, dass es Gründe gibt, warum das manifest.json / manifest.webmanifest keinen Build-Hash enthalten sollte, was einer der Gründe ist, warum es ziemlich oft von der Verarbeitung durch den Bundler ausgeschlossen wird. Ich könnte mich irren / falsch erinnern, aber möglicherweise etwas mit PWAs und dem Offline-Modus zu tun haben

Implementiert eines der Razzle-Beispielprojekte die Unterstützung von PWA (und / oder Servicemitarbeitern)?

Vielleicht weniger relevant, aber einige andere Dinge, die ich in der Vergangenheit bei Verwendung der Create-React-App in den Ordner public/ gestellt habe, sind herunterladbare Dateien, die sich auf die Website beziehen, für die jedoch dauerhafte URLs erforderlich sind. Zum Beispiel ein PDF-Dokument, mit dem beim Versenden von E-Mails usw. verknüpft werden kann

Der Versuch, nach Beispielen zu suchen, ob / warum / wann Webmanifeste vom Bundler getrennt sein sollten:

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

In diesem Beitrag befindet sich ein Kommentar, der auf https://github.com/w3c/manifest/issues/446#issuecomment -351368893 verweist

Ja, herunterladbare Dateien sollten dorthin gehen. Hm, aber wie fügen wir diese Dateien der Datei resources.json hinzu? Irgendwelche Ideen? 😀Sollen wir das Webpack dazu bringen, sie zu finden und so zu bündeln, wie sie sind? Das Ändern der Datei "resources.json" scheint hackisch.

Ich glaube nicht, dass es ein PWA-Beispiel gibt. Aber wenn sie einen einheitlichen Namen brauchen. Das muss per Webpack erledigt werden.

Ich werde das Assets-Plugin durch das Manifest-Plugin ersetzen, damit wir die Ausgabe anpassen können.

Ein neues Assets-Manifest mit allen Dateien hinzugefügt https://github.com/jaredpalmer/razzle/commit/1c6e9169e9d8eee256d0f118f8a88da8de85989f Verbesserungsvorschläge?

Habe jetzt eine kanarische Veröffentlichung gemacht :)

Ich sehe, dass das Manifest-Plugin nicht wirklich gewartet wird. Das Beste wäre, unser eigenes zu tun. Aber ich kenne derzeit niemanden außer (vielleicht) mir oder den Webpack-Leuten, die das können.

Jetzt zum kanarischen Zweig hinzugefügt. Eine Art Hack für jetzt. Aber es funktioniert und ist ein Anfang, der verbessert werden kann.

Nach einiger Überlegung werde ich dies nicht zum Kern hinzufügen.

Aber hier ist der Code, den ich mir ausgedacht habe:

        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;
          },
        })

Aber ich habe viel über Vermögenswerte gelernt;)

Es tut mir leid, dass ich seit einiger Zeit nicht mehr viel Zeit damit verbringen konnte, aber das sieht ordentlich aus. Schauen Sie sich jetzt an, wie Sie meine Inhalte auf die neueste stabile Razzle-Version aktualisieren und Ihren Vorschlag als benutzerdefiniertes Plugin ausprobieren können.

Es sieht ziemlich gut aus, aber ich bin etwas verwirrt darüber:

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

if (fileHasHash) longTermCacheFiles.add(file);

Was soll webpackOptions.fileLoaderOutputName sein? für mich scheint es immer nur undefiniert zu sein.

Nur in Razzle Canary

Ordentlich, ich habe jetzt einige Fortschritte gemacht, indem ich eine Niederlassung in meinem Projekt dazu gebracht habe, an der kanarischen Niederlassung zu arbeiten. Es funktioniert nicht ganz, im Moment scheinen meine Probleme hauptsächlich damit zu tun zu haben, den Babel Loader so zu konfigurieren, dass er Geschwisterpakete erkennt. Ich kann bauen, bekomme dann aber Probleme mit "Modul kann nicht gefunden werden", wenn ich versuche, es auszuführen.

Dies ist wahrscheinlich nicht zu interessant / nützlich, aber:

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

Aus dem Speicher habe ich die Konfiguration ursprünglich von https://github.com/jaredpalmer/razzle/issues/664 ausgeliehen

/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

und setze NODE_PATH = .. / oder so

Ok, also habe ich mich ein wenig damit beschäftigt und festgestellt, dass das Problem tatsächlich nur dazu führt, dass process.env.RAZZLE_CHUNKS_MANIFEST nicht mehr definiert wird 😅.

Das einzige, wofür ich es verwendet habe, war zu erkennen, welche Assets zwischengespeichert werden konnten. Es sieht also so aus, als ob ich in der Lage sein sollte, die neue ManifestPlugin -Konfiguration, die Sie jetzt verlinkt haben, zu testen, um sie zu ersetzen 🎉.

OK!

Ich habe in meinem Projekt ein benutzerdefiniertes Plugin erstellt, das vorerst für meinen Anwendungsfall gut genug zu funktionieren scheint. Der Code, den Sie sich ausgedacht haben, war sehr hilfreich, um diesen als Ausgangspunkt zu verwenden.

Ich habe es ein bisschen geändert, aber zu Ihrer Information, ich denke, es gibt ein Problem damit, bei dem es denkt, dass alles von file-loader weil dies Array.prototype.every() anstelle von Array.prototype.some() : !webpackOptions.fileLoaderExclude.every(re=>re.test(file.path))

Falls es nützlich ist, hier zu teilen:

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,
};

Oder sehen Sie es sich hier an: https://github.com/bootleg-rust/sites/pull/2/files#diff -59ee436c0396a1f925f067b7e7cbcdee354003236a279e0a87cf8831c7f587e3

Ah richtig ja, danke. Ich gewöhne mich immer noch an die neuen Plugin-Hooks, ich mag es 🎉!

Ich denke, das einzige Hauptproblem, das ich immer noch habe und das ich nicht lösen konnte, ist, dass das Plugin / Loader scss aus irgendeinem Grund nicht funktioniert, wenn es im Entwicklungsmodus mit razzle start aber wenn ich volle razzle build mache, scheint alles in Ordnung zu sein.

Irgendwelche Ideen, was es sein könnte? oder lohnt es sich, dies irgendwo auf ein anderes Github-Thema zu setzen?

Verwenden Sie modifyPaths auch für benutzerdefinierte Pfade, damit diese zusammengesetzt werden können.

Funktioniert nicht wie?

Kann eine neue Ausgabe sein .. :)

Egal, der Sass-Lader, der nicht funktionierte, war nichts, was mit Razzle zu tun hatte. Etwas, das mit einer Versionsinkongruenz zu tun hat, oder etwas mit der Version von react-scripts und / oder Storybook, die ich in einem Geschwisterpaket hatte, das Deps hochzog.

Hooks für Asset-Handling hinzugefügt, Schließen 😀

Ich sehe, Sie haben ein externes Plugin hinzugefügt. Ich muss das noch für Client / Server / Serverless beheben. Hast du irgendwelche Ideen dafür auf Kanarienvogel? Ein bisschen stecken.

Die Haken, die Sie jetzt verwenden, ist.

Ich sehe, Sie haben ein externes Plugin hinzugefügt. Ich muss das noch für Client / Server / Serverless beheben. Hast du irgendwelche Ideen dafür auf Kanarienvogel? Ein bisschen stecken.

Ich habe es definitiv als sehr praktisch empfunden (hauptsächlich auf dem Server), standardmäßig alle node_modules in build/server.js zu bündeln. Es scheint einfach super schön zu sein, den Ordner node_modules vollständig von meinen Docker-Bildern für die Produktion ausschließen zu können.

Trotzdem musste ich nicht verwenden / testen, wie es mit nativen / plattformspezifischen Abhängigkeiten funktioniert (ich habe das Gefühl, dass Dinge wie Imagemagick Probleme haben würden).

Mein allgemeiner Denkprozess mit dem von mir erstellten "externen" Plugin ist:

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
  ],
};

Um ehrlich zu sein, bevor ich mich für eine "richtige" Konfigurations-API dafür entscheide (insbesondere wenn es sich um einen Razzle-Core handelt), müsste ich wahrscheinlich die Webpack-Dokumente für externals etwas ausführlicher lesen verschiedene Anwendungsfälle für externe Geräte 😅.

Im Moment benutze ich es wirklich nur, um externe Geräte so zurückzusetzen, dass sie leer sind, damit ich alles in einer leicht portierbaren App bündle, die zur Laufzeit nicht auf node_modules basiert

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

krazyjakee picture krazyjakee  ·  3Kommentare

gabimor picture gabimor  ·  3Kommentare

alexjoyner picture alexjoyner  ·  3Kommentare

knipferrc picture knipferrc  ·  5Kommentare

mhuggins picture mhuggins  ·  3Kommentare