Razzle: ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ 'Cache-Control'์„ ์„ค์ •ํ•ด๋„ ์•ˆ์ „ํ•œ ๋ชจ๋“  ์ž์‚ฐ ๋ชฉ๋ก์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2020๋…„ 07์›” 31์ผ  ยท  40์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: jaredpalmer/razzle

๐Ÿš€ ๊ธฐ๋Šฅ ์š”์ฒญ

ํŒŒ์ผ ์ด๋ฆ„์— webpack [hash:8] ๋˜๋Š” [contenthash:8] ๊ฐ€ ํฌํ•จ ๋œ razzle์—์„œ ๋นŒ๋“œ ํ•œ ํŒŒ์ผ์„ ์ œ๊ณต ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด razzle ์„œ๋ฒ„์— ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์„ ์กฐ์‚ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ฒ˜์Œ ์—ฌ๊ธฐ์—์„œ ๋‚ด๊ฐ€ ๊ฒช๊ณ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋…ผ์˜ํ–ˆ๋‹ค https://github.com/jaredpalmer/razzle/pull/1368#issuecomment -664015050

๋‚˜๋Š” razzle์ด "๋ถˆ๋ณ€"(์‘๋‹ต์—์„œ Cache-Control ํ—ค๋”๋ฅผ ์„ค์ •ํ•˜๊ธฐ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ)์œผ๋กœ ๊ฐ„์ฃผ ๋  ์ˆ˜์žˆ๋Š” ์•ˆ์ „ํ•œ ํŒŒ์ผ / ์ž์‚ฐ ๋ชฉ๋ก์„ ์ƒ์„ฑํ•˜๊ณ  ๋…ธ์ถœํ•˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. chunks.json ๋ฐ / ๋˜๋Š” assets.json ํŒŒ์ผ

์ฐธ๊ณ  : ์ˆ˜๋ช…์ด ๊ธธ๊ณ  ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ์บ์‹œ ์ œ์–ด ์‘๋‹ต์„ ์„ค์ •ํ•  ๋•Œ ํŒŒ์ผ์ด ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ (ํŒŒ์ผ ์ด๋ฆ„์˜ ํ•ด์‹œ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ์ •๊ทœ์‹)์— ๋Œ€ํ•ด ์–ด๋–ค ์ข…๋ฅ˜์˜ "๊ทผ์‚ฌ์น˜"๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ ค ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์ด ์˜ค๋žซ๋™์•ˆ ๋ถˆ๋ณ€์œผ๋กœ ์บ์‹œ๋˜๊ณ  ์„œ๋ฒ„ ์ธก ์บ์‹œ ๋ฌดํšจํ™”๋กœ ๊ณ ์น  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๊ฒฐํ•˜๊ธฐ ๋งค์šฐ ๊ณ ํ†ต์Šค๋Ÿฌ์šด ๋ฌธ์ œ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ–‰๋™

ํ˜„์žฌ ๋…ธ์ถœ ๋œ json ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šด ์ด์œ ์— ๋Œ€ํ•œ ์š”์•ฝ :

  • ๋ณ€๊ฒฝ์—†์ด ์บ์‹œ ํ•  ์ˆ˜์žˆ๋Š” ๋ชจ๋“  ํŒŒ์ผ์˜ ๊ตฌ์ฒด์ ์ธ ๋ชฉ๋ก์„ ์–ป์œผ๋ ค๋ฉด (ํŒŒ์ผ์— ๋นŒ๋“œ ๋˜๋Š” ์ฝ˜ํ…์ธ  ํ•ด์‹œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—) chunks.json ๋ฐ assets.json ๋ชจ๋‘ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. chunks.json์€ ์†Œ์Šค ๋งต ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ณ  assets.json์—๋Š” chunks.json์ด์—†๋Š” png / fonts ๋“ฑ๊ณผ ๊ฐ™์€ ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • assets.json ๋ฐ chunks.json์€ ๋™์ผํ•œ ํ˜•์‹์ด ์•„๋‹ˆ๋ฏ€๋กœ (์›นํŒฉ์ด ์—ฌ๋Ÿฌ ์ฒญํฌ๋กœ ๋ถ„ํ•  ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜์—๊ฒŒ ๋‚˜ํƒ€๋‚  ์ˆ˜์žˆ๋Š” ๋ฌธ์ œ ์ผ ์ˆ˜ ์žˆ์Œ) ๋ชจ๋“  ํŒŒ์ผ์˜ ์ „์ฒด ๋ชฉ๋ก์„ ์ˆ˜์ง‘ํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ์ž„์‹œ ๋ณ€ํ™˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. /์ž์‚ฐ. ๋ช‡ ๊ฐ€์ง€ ์ฐจ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    • (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.json์— chunks: ["1", "2", "3"] ๋ฐฐ์—ด์„ ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๊ณ„ํš์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒŒ์ผ ๋ฐฐ์—ด์ด ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— (chunks.json).client.chunks ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ์ž‘์—…์„ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์†Œ ์งœ์ฆ์ด๋‚ฉ๋‹ˆ๋‹ค. (chunks.json).client.css ๋ฐ (chunks.json).client.js ๋“ฑ
  • ๋ณ€๊ฒฝํ•˜๊ธฐ ์ „์— ์—ฌ๊ธฐ์„œ client ์ฒญํฌ์—์—†๋Š” ํŒŒ์ผ์€ chunks.json ํŒŒ์ผ์—๋„ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ฒญํฌ ๋ฒˆํ˜ธ๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์†Œํ•œ ํŒŒ์ผ์— ํ‘œ์‹œ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์˜ ๋‹จ์ ์€ ์ด์ œ ๊ธฐ๋ณธ ๋ช…๋ช… ๋œ ์ฒญํฌ ( "client": {/* blah */ } )๊ฐ€ ์•„๋‹Œ ์ฒญํฌ๋ฅผ ์ฒ˜๋ฆฌ ํ•  ๋•Œ ์Šคํ‚ค๋งˆ์—์„œ chunks.json ๋ฐ assets.json ๋” ๋‹ค์–‘ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

assets.json ๋ฐ chunks.json ์‚ฌ์šฉ

ํ˜„์žฌ assets.json ๋ฐ chunks.json์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ง€๊ธˆ๊นŒ์ง€ ๋Œ€๋žต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š”ํ•˜์ง€ ์•Š์•˜๋‹ค :

  • ์•„์ง assets.json๋กœ๋“œ ๋ฐ ํ˜•์‹ ๊ฐ„์˜ ์ฐจ์ด์  ํ•ด๊ฒฐ ์ถ”๊ฐ€
  • "chunks": ["1", "2", "3"] ๋ฐ "json": "/../chunks.json" ์™€ ๊ฐ™์ด 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 ์‚ฌ์šฉํ•˜์—ฌ์ด "์บ์‹œ ๊ฐ€๋Šฅํ•œ ์ž์‚ฐ"๋ชฉ๋ก์„ ์ž‘์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•œ ํ›„์—๋Š” ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์–ด๋–ค ์ข…๋ฅ˜์˜ ์›นํŒฉ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋นŒ๋“œ์‹œ์ด ๋‘ ํŒŒ์ผ์˜ ๋ถˆ์ผ์น˜๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด ๋ชฉ์ ์„ ์œ„ํ•ด ์ฒ˜์Œ์—๋Š” ๋‚ด๊ฐ€ ํ•ด์™” ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋Ÿฐํƒ€์ž„๋ณด๋‹ค๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์กฐ์‚ฌํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ๋ณธ์ ์œผ๋กœ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•ด์‹œ ๋œ ํŒŒ์ผ์— ๋Œ€ํ•ด ์ˆ˜๋ช…์ด ๊ธด ์บ์‹œ ์ œ์–ด๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ฃผ๋กœ ํ•ด์‹œ ๋œ ํŒŒ์ผ์ด ์‹œ์ž‘๋˜๋Š” ์ด์œ ์ด๋ฏ€๋กœ ๋ชจ๋“  ํŒŒ์ผ ๋ชฉ๋ก์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆ ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ˆ„๊ตฌ์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ ๊นŒ? ๋ˆ„๊ตฌ๋ฅผ์œ„ํ•œ๊ฑฐ์•ผ?

razzle์— ์˜ํ•ด ์ƒ์„ฑ ๋ฐ ํ•ด์‹œ ๋œ ํŒŒ์ผ์— ๋Œ€ํ•ด ์ ์ ˆํ•œ ์ˆ˜๋ช… ๋ฐ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ์บ์‹œ ์ œ์–ด ์‘๋‹ต ํ—ค๋”๋ฅผ ์„ค์ •ํ•˜๋ ค๋Š” ๋ชจ๋“  ์‚ฌ์šฉ์ž.

๊ณ ๋ คํ•œ ๋Œ€์•ˆ ์„ค๋ช…

  • chunks.json ๋ฐ assets.json ํ•จ๊ป˜ ๋ฌถ์–ด ๋Ÿฐํƒ€์ž„์— ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅ / ์บ์‹œ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ํŒŒ์ผ ๋ชฉ๋ก์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค (์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๊ณ  ์ทจ์•ฝํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž„).
  • ๋นŒ๋“œ ํƒ€์ž„์— ์บ์‹œ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ ๋ชฉ๋ก์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜๋Š” ์™ธ๋ถ€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. (๋ฒ ์ดํฌ ์ธ / ์•ˆ์ •์ ์ด์–ด์•ผํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด razzle ๋ฒ„์ „์—์„œ ๊นจ์ง€๊ธฐ ์‰ฌ์šด ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค)
  • razzle์˜ ๊ธฐ๋ณธ ๊ตฌ์„ฑ์— ๋‚ด๋ถ€ ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ ์•ก์„ธ์Šคํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค (์˜ˆ : require(process.env.RAZZLE_CACHING_MANIFEST!) . ()

์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ

์ด ๋ณ€๊ฒฝ์„ ์œ„ํ•ด ๊ธฐ๊บผ์ด ๋•๊ณ  / ๊ธฐ์—ฌํ•  ์˜ํ–ฅ์ด ์žˆ์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ์•ฝ๊ฐ„์˜ ์š”์ ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (๋ฌผ๋ก  ์ด๊ฒƒ์ด ์ˆ˜๋ฝ / ํ™˜์˜๋˜๋Š” ๋ณ€๊ฒฝ์ธ์ง€ ์—ฌ๋ถ€).

๋˜ํ•œ ์ƒ๊ฐ์€, ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ญ”๊ฐ€์žˆ๋Š” ๊ฒƒ์€ ์‰ฝ๊ฒŒ / ์ผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ณด์žฅ ์ฃผ์œ„ ์•ˆ์ •์„ฑ ๋ช‡ ๊ฐ€์ง€ ๊ฒ€์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ [contenthash:8] ๋Œ€์‹  [hash:8] (๋นŒ๋“œ ํ•ด์‹œ) IF / ๊ทธ๋“ค์ด ํ•  ์ˆ˜ / : HTTPS /github.com/jaredpalmer/razzle/issues/1331

discussion enhancement help wanted razzle webpack webpack-config

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ง€๊ธˆ ์นด๋‚˜๋ฆฌ์•„๊ฐ€ ์ถœ์‹œ ๋˜์—ˆ๋‚˜์š” :)

๋ชจ๋“  40 ๋Œ“๊ธ€

์ด๊ฒƒ์€ ๊ฐ€์น˜์žˆ๋Š” ์•„์ด๋””์–ด์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์ตœ์ ํ™”์—์„œ chunkGroup ๊ตฌ์„ฑ์ด๋ผ๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ์™€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์„ค์ • ๋˜์—ˆ๋‹ค๋ฉด ๋นˆ ๋ฌธ์ž์—ด์€ "shared", "framework"๋“ฑ์ด ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

next.js๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ chunkGroups ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ด์ „ ๋ฒ„์ „๊ณผ๋„ ํ˜ธํ™˜๋˜์ง€ ์•Š์ง€๋งŒ ์ˆ˜ํ–‰๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋ฆด๋ฆฌ์Šค๊ฐ€ ํ•„์š”ํ•œ ๋ช‡ ๊ฐ€์ง€ ํฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ฝ”๋“œ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ƒ๊ฐํ•ด๋ณด์„ธ์š” ๐Ÿ˜€

next.js๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ chunkGroups ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ค ๋ฉ‹์ง€๋‹ค, ๋‚˜๋Š” ๋‹ค๋ฅธ ๋„๊ตฌ / ํ”„๋ ˆ์ž„ ์›Œํฌ๊ฐ€ ์ด๊ฒƒ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ• / ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋งํฌ / ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋˜ํ•œ ์ตœ์ ํ™”์—์„œ chunkGroup ๊ตฌ์„ฑ์ด๋ผ๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ์™€ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต๊ฐœ ๋œ ๋ฌธ์ œ? ๋” ๋งŽ์€ ์ปจํ…์ŠคํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ์–ด๋Š ๊ฒƒ์„ ์•Œ๋ ค ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์ž ์žฌ์  ์ธ ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๊ธฐ์กด 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๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋งํ•˜๊ณ  ์‹ถ์€ ๋ณต์‚ฌ ๋œ ํŒŒ์ผ์€ ๋ฒˆ ๋“ค๋Ÿฌ๊ฐ€์žˆ์„ ๋•Œ ๋‚˜์œ ์Šต๊ด€์ž…๋‹ˆ๋‹ค.

"๋ฒˆ ๋“ค๋Ÿฌ๊ฐ€์žˆ์„ ๋•Œ ๋ณต์‚ฌ ๋œ ํŒŒ์ผ์€ ๋‚˜์œ ์Šต๊ด€"์ด๋ผ๋Š” ๋œป์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋™์ž‘์€ razzle ํ”„๋กœ์ ํŠธ์˜ ์ตœ์ƒ์œ„ public/ ํด๋”์— ํŒŒ์ผ์„ ๋„ฃ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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 ๋งŒ ํฌํ•จํ•ด์•ผํ•˜๋ฉฐ ํ•ด์‹œ๋กœ ๋ฒ„์ „์ด ์ง€์ •๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์€ ์›นํŒฉ์— ์˜ํ•ด ๋ฒˆ๋“ค๋กœ ์ œ๊ณต๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋” ํฐ ํŒŒ๋น„์ฝ˜์€ ๋ฒˆ๋“ค๋กœ ์ œ๊ณต๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ create-react-app ์™€ "ํ”Œ๋Ÿฌ๊ทธ ์•ค ํ”Œ๋ ˆ์ด"ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์—๋„ ์•ฑ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์™€ ์ผ๋ถ€ ์•„์ด์ฝ˜ ๋„ ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋œ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” manifest.json / manifest.webmanifest ์— ๋นŒ๋“œ ํ•ด์‹œ๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š์•„์•ผํ•˜๋Š” ์ด์œ ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ง‰์—ฐํ•˜๊ฒŒ ๊ธฐ์–ตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฒˆ ๋“ค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ‹€๋ ธ๊ฑฐ๋‚˜ ์ž˜๋ชป ๊ธฐ์–ตํ•  ์ˆ˜ ์žˆ์ง€๋งŒ PWA ๋ฐ ์˜คํ”„๋ผ์ธ ๋ชจ๋“œ์™€ ๊ด€๋ จ์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

razzle ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ์—์„œ PWA (๋ฐ / ๋˜๋Š” ์„œ๋น„์Šค ์›Œ์ปค) ์ง€์›์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๊นŒ?

๋œ ๊ด€๋ จ์„ฑ์ด ์žˆ์ง€๋งŒ ๊ณผ๊ฑฐ์— create-react-app์„ ์‚ฌ์šฉํ•  ๋•Œ public/ ํด๋”์— ๋„ฃ์€ ๋‹ค๋ฅธ ๊ฒƒ์€ ์›น ์‚ฌ์ดํŠธ์™€ ๊ด€๋ จ๋œ ๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ์ด์ง€๋งŒ ์˜๊ตฌ URL์ด ํ•„์š”ํ•œ ๊ณณ์ž…๋‹ˆ๋‹ค. ์ด๋ฉ”์ผ ๋“ฑ์„ ๋ณด๋‚ผ ๋•Œ ๋งํฌ ํ•  ์ˆ˜์žˆ๋Š” pdf ๋ฌธ์„œ๊ฐ€์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

if / why / when ์›น ๋งค๋‹ˆํŽ˜์ŠคํŠธ๊ฐ€ ๋ฒˆ ๋“ค๋Ÿฌ์™€ ๋ถ„๋ฆฌ๋˜์–ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ์˜ ์˜ˆ๋ฅผ ์ฐพ์œผ๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค.

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 ์นด๋‚˜๋ฆฌ์•„์—์„œ๋งŒ

๊น”๋”ํ•œ, ๋‚˜๋Š” ์นด๋‚˜๋ฆฌ์•„ ๋ธŒ๋žœ์น˜์—์„œ ์ž‘์—…ํ•˜๋Š” ๋‚ด ํ”„๋กœ์ ํŠธ์— ๋ธŒ๋žœ์น˜๋ฅผ ๊ฐ€์ ธ ์™€์„œ ์•ฝ๊ฐ„์˜ ์ง„์ „์„ ์ด๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค. ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ์ œ ๋ฌธ์ œ๋Š” ์ฃผ๋กœ ํ˜•์ œ ํŒจํ‚ค์ง€๋ฅผ ์ธ์‹ํ•˜๋„๋ก ๋ฐ”๋ฒจ ๋กœ๋”๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ "๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ"๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์•„๋งˆ๋„ ๋„ˆ๋ฌด ํฅ๋ฏธ ๋กญ๊ฑฐ๋‚˜ ์œ ์šฉํ•˜์ง€๋Š” ์•Š์ง€๋งŒ :

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

์•„ ๋งž๋‹ค, ๊ณ ๋งˆ์›Œ. ๋‚˜๋Š” ์—ฌ์ „ํžˆ ์ƒˆ๋กœ์šด ํ”Œ๋Ÿฌ๊ทธ์ธ ํ›„ํฌ์— ์ต์ˆ™ํ•ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ ์œ ์ผํ•œ ์ฃผ์š” ๋ฌธ์ œ๋Š” razzle start ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ ์‹คํ–‰ํ•  ๋•Œ ์–ด๋–ค ์ด์œ ๋กœ 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 ์ฝ”์–ด์—์žˆ์„ ๊ฒฝ์šฐ) ์›นํŒฉ ๋ฌธ์„œ์—์„œ externals ์— ๋Œ€ํ•ด ์ข€ ๋” ๊นŠ์ด ์ฝ์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™ธ๋ถ€์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€ ๐Ÿ˜….

ํ˜„์žฌ๋Š” ์™ธ๋ถ€๋ฅผ ๋น„์›Œ ๋‘๋Š” ๋ฐ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋Ÿฐํƒ€์ž„์— node_modules์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ์‰ฝ๊ฒŒ ์ด์‹ ๊ฐ€๋Šฅํ•œ ์•ฑ์— ๋ชจ๋“  ๊ฒƒ์„ ๋ฒˆ๋“ค๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰