Razzle: выставить список всех активов, которые можно безопасно установить неизменяемым `Cache-Control`

Созданный на 31 июл. 2020  ·  40Комментарии  ·  Источник: jaredpalmer/razzle

🚀 Запрос функции

Я исследовал лучший способ добавить промежуточное ПО к моему серверу razzle, чтобы обнаруживать, когда он обслуживает файл, созданный razzle, который включает в себя веб-пакет [hash:8] или [contenthash:8] в имени файла. Сначала я обсудил некоторые проблемы, с которыми я сталкиваюсь здесь https://github.com/jaredpalmer/razzle/pull/1368#issuecomment -664015050

Я хотел бы, чтобы razzle сгенерировал и предоставил список файлов / активов, которые можно было бы считать "неизменными" (для целей установки заголовков Cache-Control в ответах) таким образом, чтобы их было легко использовать без дополнительного преобразования файлы chunks.json и / или assets.json

ПРИМЕЧАНИЕ: при установке долгоживущих и неизменяемых ответов на управление кешем я хочу избежать какого-либо «приближения» к тому, можно ли считать файл неизменяемым (регулярное выражение AKA для обнаружения хэша в имени файла), потому что ложное срабатывание может привести к файл постоянно кэшируется и не может быть исправлен с помощью аннулирования кеша на стороне сервера, что может быть очень болезненной проблемой для решения.

Текущее поведение

TL; DR о том, почему сложно использовать открытые в настоящее время файлы json:

  • Чтобы получить конкретный список всех файлов, которые можно безопасно кэшировать неизменяемым образом (поскольку в них есть хэши сборки или содержимого), мне нужно использовать как chunks.json и assets.json . chunks.json включает файлы исходных карт, а assets.json имеет такие файлы, как png / fonts и т. д., а chunks.json - нет.
  • Файлы assets.json и chunks.json находятся в разных форматах (возможно, это проблема, которая проявляется для меня, потому что я позволяю webpack разбивать вещи на несколько частей), поэтому требуется различное специальное преобразование для сопоставления полного списка всех файлов. /ресурсы. Вот некоторые отличия:

    • Кажется, что для любого фрагмента, который не находится в (assets.json).client (например: "client": { "js": "/static/js/bundle.6fc534aa.js" } ), assets.json группирует все другие активы под пустой строкой (например: "": { "js": "/static/js/0.cb47cee9.chunk.js" } ).

    • если в группе chunks.json присутствует только один файл, это будет массив с одним элементом в нем (например: "client": { "css": ["filename.css"] } ), если в assets.json присутствует только один файл, это будет просто одиночная строка (например: "client": { "css": "filename.css" } ).

  • Мой assets.json в настоящее время содержит "json": "/../chunks.json" который, по моему мнению, не должен быть там (я не уверен, ошибка это или нет), но мне нужно вручную удалить это при составлении списка файлы, которым могут быть предоставлены долгоживущие заголовки ответов cache-Control.
  • План по добавлению массива chunks: ["1", "2", "3"] в chunks.json несколько раздражает, потому что это означает, что мне нужно проделать дополнительную работу, чтобы отфильтровать (chunks.json).client.chunks потому что он не содержит массив файлов вроде (chunks.json).client.css и (chunks.json).client.js и т. Д.
  • До изменения, которое я сделал здесь, файлы не в чанке client даже не отображались в файле chunks.json . Я сделал / предложил изменить его, чтобы использовать номер (а) блока в качестве ключа, потому что, по крайней мере, они затем появляются в файле. Обратной стороной этого является то, что теперь chunks.json и assets.json различаются по своей схеме при работе с блоками, которые не являются первичными именованными блоками ( "client": {/* blah */ } ).

с использованием assets.json и chunks.json

В настоящее время я использую assets.json и chunks.json, это то, что мне приходилось делать примерно до сих пор.

У меня нет:

  • добавлена ​​загрузка assets.json и устранение различий между форматами
  • Фильтрация файлов / полей в json, которые, как я знаю, не предназначены для использования, например "chunks": ["1", "2", "3"] и "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}`,
      );
    },
  }),
);

Четкое и краткое описание текущего поведения / использования.

Желаемое поведение

Вероятно, есть много способов сделать это, но главное, что я хочу, - это просто способ загрузить массив всех кешируемых / неизменяемых активов, сгенерированных сборкой razzle. результат может выглядеть примерно так:

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

Предлагаемое решение

Я не полностью исследовал, какое было бы хорошее решение, но после попытки составить этот список «кэшируемых активов» во время выполнения с использованием assets.json и chunks.json я почти убедился, что как минимум, лучший способ добиться этого - во время сборки с помощью какого-либо плагина webpack и обойти несоответствия этих двух файлов.

Для моих целей я, вероятно, сначала начну изучать, как добиться этого с помощью плагина, а не во время выполнения, как я делал, но я думаю, что было бы очень полезно иметь эту встроенную функцию по умолчанию. Возможность установить долгоживущий контроль кеширования для хешированных файлов во многом является причиной того, что они хешируются с самого начала, поэтому отображение списка всех этих файлов кажется уместным.

На кого это влияет? Это кому?

Любые пользователи, которые хотят установить соответствующие долгоживущие и неизменяемые заголовки ответов для управления кешем для файлов, сгенерированных и хешированных с помощью razzle.

Опишите альтернативы, которые вы рассмотрели

  • Сгенерируйте список всех неизменяемых / кешируемых файлов во время выполнения путем объединения chunks.json и assets.json (кажется подверженным ошибкам и хрупким).
  • Создайте внешний плагин для предварительного создания списка кэшируемых файлов во время сборки. (кажется, возможно, хрупким в разных версиях razzle для функции, которая, кажется, должна быть встроенной / стабильной)
  • Добавьте его как внутренний плагин в конфигурацию razzle по умолчанию и предоставьте способ доступа к нему по умолчанию, например: require(process.env.RAZZLE_CACHING_MANIFEST!) . ()

Дополнительный контекст

Я был бы готов помочь / внести свой вклад в внесение этого изменения, но мне может понадобиться немного указать в правильном направлении (и, конечно, будет ли это изменение принято / приветствуется).

Также подумайте, что наличие чего-то подобного может упростить некоторые тесты / стабильность для обеспечения того, чтобы вещи использовали [contenthash:8] вместо [hash:8] (хэш сборки), если / когда они могут https: / /github.com/jaredpalmer/razzle/issues/1331

discussion enhancement help wanted razzle webpack webpack-config

Самый полезный комментарий

Сделал сейчас канарейку :)

Все 40 Комментарий

Это действительно кажется стоящей идеей.

Это также связано с другой проблемой - конфигурацией chunkGroup при оптимизации. Потому что, если бы это было настроено, пустая строка была бы «разделяемой», «структурой» и т.

Если вы посмотрите на next.js, они используют такую ​​конфигурацию chunkGroups.

Когда мы изменим это, это также станет обратно несовместимым, но это необходимо сделать. У меня есть еще несколько больших изменений, которые также нуждаются в крупном выпуске.

Но не стесняйтесь придумывать код, который решает эту проблему 😀

Если вы посмотрите на next.js, они используют такую ​​конфигурацию chunkGroups.

О, круто, я не понимаю, если / как другие инструменты / фреймворки подходят к этому, у вас есть ссылка / примеры?

Это также связано с другой проблемой - конфигурацией chunkGroup при оптимизации.

Открытая проблема с razzle? не могли бы вы указать мне, какой из них, чтобы я мог получить больше контекста 😄

Я действительно думаю, что одним из возможных способов решения этой проблемы является более строгое определение формы / схемы существующих chunks.json и assets.json . Вероятно, необходимо будет внимательно рассмотреть (и иметь большой удар версии), но если есть примеры того, как другие фреймворки и т.Д. Решили проблему, может иметь смысл следовать аналогичному направлению

1361 # 1370

А также

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

Не уверен, как они делают манифест.

Взгляните на https://github.com/jaredpalmer/razzle/issues/1377 сейчас, добавлен новый пример :)

@fivethreeo Мне не удалось уделить больше времени конкретно этой проблеме 😅, я обязательно постараюсь потратить некоторое время на опробование пререлиза v4. Если вы думаете, что он готов к этому, я, надеюсь, постараюсь опробовать его в ближайшие пару дней.

Не уверен, что это интересно, но я сделал то, над чем сейчас работаю, здесь .

Мне очень нравится v4, потому что это, надеюсь, означает, что я могу удалить столько "плагинов" переопределений, которые я должен установить здесь , особенно для машинописного текста.

Кэшируемые активы здесь .

Все файлы теперь используют Contenthash. Я бы сказал, что скопированные файлы - плохая практика, когда у нас есть сборщик.

Я не уверен, что понимаю, что вы имеете в виду, говоря «Скопированные файлы, я бы сказал, плохая практика, когда у нас есть сборщик».

В настоящее время поведение таково, что если вы поместите какие-либо файлы в папку верхнего уровня public/ в вашем проекте razzle.

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

Они копируются в статические активы, когда вы razzle build

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

Я подумал, что было бы желательно вести список всех активов, которые были скопированы во время сборки, чтобы они были специально настроены отдельно для применения кеш-контроля.

Я думаю, что аргумент против этого (который я могу придумать) будет заключаться в том, что пользователю может не быть необходимости различать файлы, скопированные razzle во время сборки, и те, которые могли быть вручную помещены туда вне razzle build

Я думаю, что public должен содержать только robots.txt и favicon.ico, и они не будут версироваться по хешам.

Все остальное должно быть включено в пакет webpack. Любые значки большего размера должны быть объединены.

Возможно, но даже если вы хотите поддерживать совместимость «plug and play» со значением по умолчанию create-react-app возможно, стоит учесть, что манифест приложения и некоторые значки также будут присутствовать там .

Я часто помню, что были причины, по которым manifest.json / manifest.webmanifest не должен содержать хэш сборки, что является одной из причин, по которым он довольно часто исключается из обработки сборщиком. Я могу ошибаться / забывать, но, возможно, что-то связано с PWA и автономным режимом

Реализует ли какой-либо из примеров проектов razzle поддержку PWA (и / или сервис-воркеров)?

Возможно, менее актуально, но некоторые другие вещи, которые я помещал в папку public/ в прошлом при использовании приложения create-response-app, являются загружаемыми файлами, связанными с веб-сайтом, но для которых требуются постоянные URL-адреса. Например, иметь PDF-документ, на который можно ссылаться при отправке электронных писем и т. Д. 🤷

Попытка найти примеры того, если / почему / когда веб-манифесты должны быть отделены от сборщика:

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

В этом сообщении есть комментарий со ссылкой на https://github.com/w3c/manifest/issues/446#issuecomment -351368893.

Да, загружаемые файлы должны быть туда. Хм, но как нам добавить эти файлы в assets.json? Любые идеи? 😀Можно ли сделать так, чтобы webpack находил их и собирал как есть? Изменение assets.json кажется хакерским.

Я не думаю, что есть пример PWA. Но если им нужно последовательное имя. Это нужно делать с помощью webpack.

Я заменю плагин ресурсов на плагин манифеста, чтобы мы могли адаптировать вывод.

Добавлен новый манифест ассетов со всеми файлами https://github.com/jaredpalmer/razzle/commit/1c6e9169e9d8eee256d0f118f8a88da8de85989f есть предложения по улучшению?

Сделал сейчас канарейку :)

Я вижу, что плагин манифеста на самом деле не поддерживается. Лучше всего сделать свое собственное. Но в настоящее время я не знаю никого, кроме (может быть) меня или тех, кто умеет это делать.

Добавлен в ветку канареек. Что-то вроде хака. Но это работает, и это начало, которое можно улучшить.

После некоторого размышления я не буду добавлять это в ядро.

Но вот код, который я придумал:

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

Но я многое узнал об активах;)

Извините, я не мог уделять этому много времени, но это выглядит аккуратно. Взглянул на обновление моих материалов до последней стабильной версии razzle и опробовал ваше предложение в качестве настраиваемого плагина.

Выглядит неплохо, но меня это немного смущает:

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

if (fileHasHash) longTermCacheFiles.add(file);

Что означает webpackOptions.fileLoaderOutputName ? для меня это всегда кажется неопределенным.

Только в канарейке razzle

Аккуратно, сейчас я добился некоторого прогресса в создании ветки в моем проекте, работающей над веткой канарейки. Это не совсем работает, на данный момент мои проблемы, в основном, связаны с настройкой загрузчика babel для распознавания родственных пакетов. Я могу собрать, но при попытке запустить возникают проблемы «не могу найти модуль».

Это, вероятно, не слишком интересно / полезно, но:

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

по памяти я изначально позаимствовал конфигурацию с 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

и установите NODE_PATH = .. / или что-нибудь

Может, здесь стоит кое-что изменить:

https://github.com/jaredpalmer/razzle/blob/canary/packages/razzle/config/modules.js

Хорошо, так что немного углубившись в это, я только что понял, что проблема на самом деле просто привела к тому, что process.env.RAZZLE_CHUNKS_MANIFEST не определяется 😅.

Единственное, для чего я его использовал, это для определения того, какие ресурсы можно кэшировать, так что похоже, что я смогу дать новую конфигурацию ManifestPlugin вы связали, и заменить ее 🎉.

ОК!

Я создал специальный плагин в своем проекте, который на данный момент работает достаточно хорошо для моего варианта использования. Код, который вы придумали, был очень полезным, взяв его за отправную точку.

Я немного изменил его, но, к вашему сведению, я думаю, что есть проблема, когда он думает, что все обрабатывается file-loader потому что здесь используется Array.prototype.every() вместо Array.prototype.some() : !webpackOptions.fileLoaderExclude.every(re=>re.test(file.path))

Если будет полезно поделиться здесь:

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

Или можете посмотреть здесь https://github.com/bootleg-rust/sites/pull/2/files#diff -59ee436c0396a1f925f067b7e7cbcdee354003236a279e0a87cf8831c7f587e3

Ах да, спасибо. Я все еще привыкаю к ​​новым хукам плагинов, мне это нравится 🎉!

Я думаю, что единственная основная проблема, которую я до сих пор не могу решить, заключается в том, что по какой-то причине плагин / загрузчик scss не работает при работе в режиме разработки с использованием razzle start но если я сделаю полный razzle build все будет в порядке.

Есть идеи, что это может быть? или стоит поместить это где-нибудь в другой выпуск github?

Также используйте modifyPaths для настраиваемых путей, чтобы их можно было составить.

Не работает как?

Может новый выпуск .. :)

Неважно, что загрузчик sass не работает, не было ничего специфичного для razzle. что-то связано с несовпадением версий или с версией react-scripts и / или сборника рассказов, которые у меня были в родственном пакете, который поднимал deps.

Добавлены хуки для работы с активами, закрытия 😀

Я вижу, вы добавили внешний плагин. Мне все еще нужно исправить это для клиент / сервер / без сервера. Есть идеи для этого в канарейке? Немного застрял.

Крючки, которые вы используете сейчас, есть.

Я вижу, вы добавили внешний плагин. Мне все еще нужно исправить это для клиент / сервер / без сервера. Есть идеи для этого в канарейке? Немного застрял.

Я определенно нашел очень удобным (в основном на сервере) по умолчанию объединять все node_modules в build/server.js . Возможность полностью исключить папку node_modules из моих производственных изображений докеров кажется очень приятной.

Сказав, что у меня не было необходимости использовать / тестировать, как он работает с любыми собственными / зависящими от платформы зависимостями (я чувствую, что такие вещи, как imagemagick, будут иметь проблемы)

Мой общий мыслительный процесс с плагином "externals", который я сделал, таков:

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

Честно говоря, прежде чем выбирать «правильный» конфигурационный API для этого (особенно, если он будет в ядре razzle), мне, вероятно, придется прочитать документацию webpack для externals немного подробнее о различные варианты использования внешних элементов 😅.

На данный момент я действительно использую его только для сброса внешних элементов, чтобы они были пустыми, чтобы я получил все в комплекте в легко переносимое приложение, которое не полагается на node_modules во время выполнения

Была ли эта страница полезной?
0 / 5 - 0 рейтинги