vike 0.4.160-commit-937d8d5 → 0.4.160-commit-d574f51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/cjs/node/cli/bin.js +5 -0
  2. package/dist/cjs/node/plugin/plugins/buildConfig/fixServerAssets.js +148 -0
  3. package/dist/cjs/node/plugin/plugins/buildConfig.js +34 -16
  4. package/dist/cjs/node/plugin/plugins/distFileNames.js +9 -1
  5. package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +7 -2
  6. package/dist/cjs/node/plugin/plugins/importBuild/index.js +4 -7
  7. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +6 -1
  8. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +2 -1
  9. package/dist/cjs/node/plugin/utils.js +1 -0
  10. package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +38 -38
  11. package/dist/cjs/utils/projectInfo.js +1 -1
  12. package/dist/esm/client/client-routing-runtime/index.d.ts +1 -1
  13. package/dist/esm/client/client-routing-runtime/index.js +1 -1
  14. package/dist/esm/node/cli/bin.js +3 -1
  15. package/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.d.ts +13 -0
  16. package/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.js +142 -0
  17. package/dist/esm/node/plugin/plugins/buildConfig.d.ts +2 -0
  18. package/dist/esm/node/plugin/plugins/buildConfig.js +35 -17
  19. package/dist/esm/node/plugin/plugins/distFileNames.js +9 -1
  20. package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +8 -3
  21. package/dist/esm/node/plugin/plugins/importBuild/index.d.ts +6 -1
  22. package/dist/esm/node/plugin/plugins/importBuild/index.js +4 -7
  23. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.d.ts +2 -0
  24. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +5 -0
  25. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +2 -1
  26. package/dist/esm/node/plugin/utils.d.ts +1 -0
  27. package/dist/esm/node/plugin/utils.js +1 -0
  28. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.d.ts +6 -5
  29. package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +38 -38
  30. package/dist/esm/utils/getOutDirs.d.ts +1 -0
  31. package/dist/esm/utils/projectInfo.d.ts +2 -2
  32. package/dist/esm/utils/projectInfo.js +1 -1
  33. package/package.json +1 -1
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  const cac_1 = require("cac");
4
7
  const path_1 = require("path");
5
8
  const runPrerender_js_1 = require("../prerender/runPrerender.js");
6
9
  const utils_js_1 = require("./utils.js");
10
+ const picocolors_1 = __importDefault(require("@brillout/picocolors"));
7
11
  const cli = (0, cac_1.cac)(utils_js_1.projectInfo.projectName);
8
12
  cli
9
13
  .command('prerender', 'Pre-render the HTML of your pages', { allowUnknownOptions: true })
@@ -30,6 +34,7 @@ function assertOptions() {
30
34
  '--outDir',
31
35
  '--configFile'
32
36
  ].includes(option), 'Unknown option: ' + option);
37
+ (0, utils_js_1.assertWarning)(false, `You set ${picocolors_1.default.cyan(option)}, but passing options to ${picocolors_1.default.cyan('$ vike prerender')} is deprecated: use the config file instead. See https://vike.dev/command-prerender.`, { onlyOnce: true });
33
38
  });
34
39
  }
35
40
  // Listen to unknown commands
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fixServerAssets_isEnabled = exports.fixServerAssets = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = require("fs");
10
+ const utils_js_1 = require("../../utils.js");
11
+ const virtualFilePageConfigValuesAll_js_1 = require("../../../shared/virtual-files/virtualFilePageConfigValuesAll.js");
12
+ const buildConfig_js_1 = require("../buildConfig.js");
13
+ /**
14
+ * true => use workaround config.build.ssrEmitAssets
15
+ * false => use workaround extractAssets plugin
16
+ *
17
+ * Only used by V1 design.
18
+ */
19
+ function fixServerAssets_isEnabled() {
20
+ // We currently apply the workaround iff V1 design.
21
+ // Shall we allow the user to toggle between the two workarounds? E.g. based on https://vike.dev/includeAssetsImportedByServer.
22
+ return true;
23
+ }
24
+ exports.fixServerAssets_isEnabled = fixServerAssets_isEnabled;
25
+ /** https://github.com/vikejs/vike/issues/1339 */
26
+ async function fixServerAssets(outDirs) {
27
+ const clientManifest = await loadManifest(outDirs.outDirClient);
28
+ const serverManifest = await loadManifest(outDirs.outDirServer);
29
+ const { clientManifestMod, filesToCopy } = addServerAssets(clientManifest, serverManifest);
30
+ await copyAssets(filesToCopy, outDirs);
31
+ return clientManifestMod;
32
+ }
33
+ exports.fixServerAssets = fixServerAssets;
34
+ async function loadManifest(outDir) {
35
+ const manifestFilePath = path_1.default.posix.join(outDir, buildConfig_js_1.manifestTempFile);
36
+ const manifestFileContent = await promises_1.default.readFile(manifestFilePath, 'utf-8');
37
+ (0, utils_js_1.assert)(manifestFileContent);
38
+ const manifest = JSON.parse(manifestFileContent);
39
+ (0, utils_js_1.assert)(manifest);
40
+ return manifest;
41
+ }
42
+ async function copyAssets(filesToCopy, { outDirClient, outDirServer }) {
43
+ const assetsDirServer = path_1.default.posix.join(outDirServer, 'assets');
44
+ if (!filesToCopy.length)
45
+ return;
46
+ (0, utils_js_1.assert)((0, fs_1.existsSync)(assetsDirServer));
47
+ const concurrencyLimit = (0, utils_js_1.pLimit)(10);
48
+ await Promise.all(filesToCopy.map((file) => concurrencyLimit(() => promises_1.default.cp(path_1.default.posix.join(outDirServer, file), path_1.default.posix.join(outDirClient, file), {
49
+ recursive: true
50
+ }))));
51
+ await promises_1.default.rm(assetsDirServer, { recursive: true });
52
+ }
53
+ // Add serverManifest resources to clientManifest
54
+ function addServerAssets(clientManifest, serverManifest) {
55
+ var _a, _b;
56
+ const entriesClient = new Map();
57
+ const entriesServer = new Map();
58
+ for (const [key, entry] of Object.entries(clientManifest)) {
59
+ const pageId = getPageId(key);
60
+ if (!pageId)
61
+ continue;
62
+ const resources = collectResources(entry, clientManifest);
63
+ (0, utils_js_1.assert)(!entriesClient.has(pageId));
64
+ entriesClient.set(pageId, { key, ...resources });
65
+ }
66
+ for (const [key, entry] of Object.entries(serverManifest)) {
67
+ const pageId = getPageId(key);
68
+ if (!pageId)
69
+ continue;
70
+ const resources = collectResources(entry, serverManifest);
71
+ (0, utils_js_1.assert)(!entriesServer.has(pageId));
72
+ entriesServer.set(pageId, resources);
73
+ }
74
+ let filesToCopy = [];
75
+ for (const [pageId, entryClient] of entriesClient.entries()) {
76
+ const cssToAdd = [];
77
+ const assetsToAdd = [];
78
+ const entryServer = entriesServer.get(pageId);
79
+ if (entryServer) {
80
+ cssToAdd.push(...entryServer.css
81
+ .filter((cssServer) => !entryClient.css.some((cssClient) => cssServer.hash === cssClient.hash))
82
+ .map((css) => css.src));
83
+ assetsToAdd.push(...entryServer.assets
84
+ .filter((assertServer) => !entryClient.assets.some((assetClient) => assertServer.hash === assetClient.hash))
85
+ .map((asset) => asset.src));
86
+ }
87
+ const { key } = entryClient;
88
+ if (cssToAdd.length) {
89
+ filesToCopy.push(...cssToAdd);
90
+ (_a = clientManifest[key]).css ?? (_a.css = []);
91
+ clientManifest[key].css?.push(...cssToAdd);
92
+ }
93
+ if (assetsToAdd.length) {
94
+ filesToCopy.push(...assetsToAdd);
95
+ (_b = clientManifest[key]).assets ?? (_b.assets = []);
96
+ clientManifest[key].assets?.push(...assetsToAdd);
97
+ }
98
+ }
99
+ const clientManifestMod = clientManifest;
100
+ filesToCopy = (0, utils_js_1.unique)(filesToCopy);
101
+ return { clientManifestMod, filesToCopy };
102
+ }
103
+ function getPageId(key) {
104
+ // Normalize from:
105
+ // ../../virtual:vike:pageConfigValuesAll:client:/pages/index
106
+ // to:
107
+ // virtual:vike:pageConfigValuesAll:client:/pages/index
108
+ // (This seems to be needed only for vitest tests that use Vite's build() API with an inline config.)
109
+ key = key.substring(key.indexOf('virtual:vike'));
110
+ const result = (0, virtualFilePageConfigValuesAll_js_1.isVirtualFileIdPageConfigValuesAll)(key);
111
+ return result && result.pageId;
112
+ }
113
+ function collectResources(entryRoot, manifest) {
114
+ const css = [];
115
+ const assets = [];
116
+ const entries = new Set([entryRoot]);
117
+ for (const entry of entries) {
118
+ for (const entryImport of entry.imports ?? []) {
119
+ entries.add(manifest[entryImport]);
120
+ }
121
+ const entryCss = entry.css ?? [];
122
+ if (entry.file.endsWith('.css'))
123
+ entryCss.push(entry.file);
124
+ for (const src of entryCss) {
125
+ const hash = getHash(src);
126
+ css.push({ src, hash });
127
+ }
128
+ const entryAssets = entry.assets ?? [];
129
+ for (const src of entryAssets) {
130
+ const hash = getHash(src);
131
+ assets.push({ src, hash });
132
+ }
133
+ }
134
+ return { css, assets };
135
+ }
136
+ // Use the hash of resources to determine whether they are equal. We need this, otherwise we get:
137
+ // ```html
138
+ // <head>
139
+ // <link rel="stylesheet" type="text/css" href="/assets/static/onRenderClient.2j6TxKIB.css">
140
+ // <link rel="stylesheet" type="text/css" href="/assets/static/onRenderHtml.2j6TxKIB.css">
141
+ // </head>
142
+ // ```
143
+ function getHash(src) {
144
+ // src is guarenteed to end with `.[hash][extname]`, see distFileNames.ts
145
+ const hash = src.split('.').at(-2);
146
+ (0, utils_js_1.assert)(hash);
147
+ return hash;
148
+ }
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.analyzeClientEntries = exports.assertRollupInput = exports.buildConfig = void 0;
6
+ exports.manifestTempFile = exports.analyzeClientEntries = exports.assertRollupInput = exports.buildConfig = void 0;
7
7
  const utils_js_1 = require("../utils.js");
8
8
  const getVikeConfig_js_1 = require("./importUserCode/v1-design/getVikeConfig.js");
9
9
  const helpers_js_1 = require("../../../shared/page-configs/helpers.js");
@@ -15,12 +15,17 @@ const module_1 = require("module");
15
15
  const getClientEntryFilePath_js_1 = require("../../shared/getClientEntryFilePath.js");
16
16
  const promises_1 = __importDefault(require("fs/promises"));
17
17
  const path_1 = __importDefault(require("path"));
18
+ const fixServerAssets_js_1 = require("./buildConfig/fixServerAssets.js");
19
+ const index_js_1 = require("./importBuild/index.js");
18
20
  // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
19
21
  const importMetaUrl = `file://${__filename}`;
20
22
  const require_ = (0, module_1.createRequire)(importMetaUrl);
21
23
  const manifestTempFile = '_temp_manifest.json';
24
+ exports.manifestTempFile = manifestTempFile;
22
25
  function buildConfig() {
23
- let generateManifest;
26
+ let isServerAssetsFixEnabled;
27
+ let isSsrBuild;
28
+ let outDirs;
24
29
  return {
25
30
  name: 'vike:buildConfig',
26
31
  apply: 'build',
@@ -34,16 +39,26 @@ function buildConfig() {
34
39
  (0, utils_js_1.assert)(Object.keys(entries).length > 0);
35
40
  config.build.rollupOptions.input = (0, utils_js_1.injectRollupInputs)(entries, config);
36
41
  addLogHook();
42
+ outDirs = (0, utils_js_1.getOutDirs)(config);
43
+ {
44
+ isServerAssetsFixEnabled = (await (0, getVikeConfig_js_1.isV1Design)(config, false)) && (0, fixServerAssets_js_1.fixServerAssets_isEnabled)();
45
+ if (isServerAssetsFixEnabled) {
46
+ // https://github.com/vikejs/vike/issues/1339
47
+ config.build.ssrEmitAssets = true;
48
+ // Required if `ssrEmitAssets: true`, see https://github.com/vitejs/vite/pull/11430#issuecomment-1454800934
49
+ config.build.cssMinify = 'esbuild';
50
+ }
51
+ }
37
52
  }
38
53
  },
39
54
  config(config) {
40
55
  assertNodeEnv();
41
- generateManifest = !(0, utils_js_1.viteIsSSR)(config);
56
+ isSsrBuild = (0, utils_js_1.viteIsSSR)(config);
42
57
  return {
43
58
  build: {
44
59
  outDir: (0, utils_js_1.resolveOutDir)(config),
45
- manifest: generateManifest ? manifestTempFile : false,
46
- copyPublicDir: !(0, utils_js_1.viteIsSSR)(config)
60
+ manifest: manifestTempFile,
61
+ copyPublicDir: !isSsrBuild
47
62
  }
48
63
  };
49
64
  },
@@ -51,20 +66,23 @@ function buildConfig() {
51
66
  assertNodeEnv();
52
67
  },
53
68
  async writeBundle(options, bundle) {
54
- assertNodeEnv();
55
- const manifestEntry = bundle[manifestTempFile];
56
- /* Fails with @vitejs/plugin-legacy because writeBundle() is called twice during the client build (once for normal client assets and a second time for legacy assets), see reproduction at https://github.com/vikejs/vike/issues/1154
57
- assert(generateManifest === !!manifestEntry)
58
- */
59
- if (manifestEntry) {
60
- const { dir } = options;
61
- (0, utils_js_1.assert)(dir);
62
- const manifestFilePathOld = path_1.default.join(dir, manifestEntry.fileName);
69
+ if (isSsrBuild) {
63
70
  // Ideally we'd move dist/_temp_manifest.json to dist/server/client-assets.json instead of dist/assets.json
64
71
  // - But we can't because there is no guarentee whether dist/server/ is generated before or after dist/client/ (generating dist/server/ after dist/client/ erases dist/server/client-assets.json)
65
72
  // - We'll able to do so once we replace `$ vite build` with `$ vike build`
66
- const manifestFilePathNew = path_1.default.join(dir, '..', 'assets.json');
67
- await promises_1.default.rename(manifestFilePathOld, manifestFilePathNew);
73
+ const assetsJsonFilePath = path_1.default.posix.join(outDirs.outDirRoot, 'assets.json');
74
+ const clientManifestFilePath = path_1.default.posix.join(outDirs.outDirClient, manifestTempFile);
75
+ const serverManifestFilePath = path_1.default.posix.join(outDirs.outDirServer, manifestTempFile);
76
+ if (!isServerAssetsFixEnabled) {
77
+ await promises_1.default.copyFile(clientManifestFilePath, assetsJsonFilePath);
78
+ }
79
+ else {
80
+ const clientManifestMod = await (0, fixServerAssets_js_1.fixServerAssets)(outDirs);
81
+ await promises_1.default.writeFile(assetsJsonFilePath, JSON.stringify(clientManifestMod, null, 2), 'utf-8');
82
+ }
83
+ await promises_1.default.rm(clientManifestFilePath);
84
+ await promises_1.default.rm(serverManifestFilePath);
85
+ await (0, index_js_1.set_constant_ASSETS_MAP)(options, bundle);
68
86
  }
69
87
  }
70
88
  };
@@ -24,9 +24,17 @@ function distFileNames() {
24
24
  if (!('chunkFileNames' in rollupOutput)) {
25
25
  rollupOutput.chunkFileNames = (chunkInfo) => getChunkFileName(chunkInfo, config);
26
26
  }
27
- if (!('assertUsage' in rollupOutput)) {
27
+ if (!('assetFileNames' in rollupOutput)) {
28
28
  rollupOutput.assetFileNames = (chunkInfo) => getAssetFileName(chunkInfo, config);
29
29
  }
30
+ else {
31
+ // If a user needs this:
32
+ // - assertUsage() that the naming provided by the user ends with `.[hash][extname]`
33
+ // - It's needed for getHash() of fixServerAssets()
34
+ // - Asset URLs should always contain a hash: it's paramount for caching assets.
35
+ // - If rollupOutput.assetFileNames is a function then use a wrapper function to apply the assertUsage()
36
+ (0, utils_js_1.assertUsage)(false, "Setting config.build.rollupOptions.output.assetFileNames is currently forbidden. (Contact a maintainer if you need this as it's possible to support this.)");
37
+ }
30
38
  });
31
39
  }
32
40
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- // Alternative: use `ssrEmitAssets: true`
3
- // - See https://github.com/vitejs/vite/pull/11430
2
+ // Remove this workaround if the other workaround config.build.ssrEmitAssets turns out to be reliable.
3
+ // - Remove this file then revert this commit: https://github.com/vikejs/vike/commit/805a18974f13420a78fcc30fdd676696e405c3ca
4
4
  var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  return (mod && mod.__esModule) ? mod : { "default": mod };
6
6
  };
@@ -9,10 +9,12 @@ exports.extractAssetsRE = exports.extractAssetsPlugin = void 0;
9
9
  const utils_js_1 = require("../utils.js");
10
10
  const extractAssetsQuery_js_1 = require("../../shared/extractAssetsQuery.js");
11
11
  const getConfigVike_js_1 = require("../../shared/getConfigVike.js");
12
+ const getVikeConfig_js_1 = require("./importUserCode/v1-design/getVikeConfig.js");
12
13
  const isAsset_js_1 = require("../shared/isAsset.js");
13
14
  const parseEsModule_js_1 = require("../shared/parseEsModule.js");
14
15
  const removeSourceMap_js_1 = require("../shared/removeSourceMap.js");
15
16
  const picocolors_1 = __importDefault(require("@brillout/picocolors"));
17
+ const fixServerAssets_js_1 = require("./buildConfig/fixServerAssets.js");
16
18
  const extractAssetsRE = /(\?|&)extractAssets(?:&|$)/;
17
19
  exports.extractAssetsRE = extractAssetsRE;
18
20
  const rawRE = /(\?|&)raw(?:&|$)/;
@@ -24,6 +26,7 @@ const debugEnabled = (0, utils_js_1.isDebugEnabled)(debugNamespace);
24
26
  function extractAssetsPlugin() {
25
27
  let config;
26
28
  let configVike;
29
+ let isServerAssetsFixEnabled;
27
30
  return [
28
31
  // This plugin removes all JavaScript from server-side only code, so that only CSS imports remains. (And also satic files imports e.g. `import logoURL from './logo.svg.js'`).
29
32
  {
@@ -35,6 +38,7 @@ function extractAssetsPlugin() {
35
38
  if (!extractAssetsRE.test(id)) {
36
39
  return;
37
40
  }
41
+ (0, utils_js_1.assert)(!isServerAssetsFixEnabled);
38
42
  (0, utils_js_1.assert)(configVike.includeAssetsImportedByServer);
39
43
  (0, utils_js_1.assert)(!(0, utils_js_1.viteIsSSR_options)(options));
40
44
  const importStatements = await (0, parseEsModule_js_1.getImportStatements)(src);
@@ -132,6 +136,7 @@ function extractAssetsPlugin() {
132
136
  async configResolved(config_) {
133
137
  configVike = await (0, getConfigVike_js_1.getConfigVike)(config_);
134
138
  config = config_;
139
+ isServerAssetsFixEnabled = (await (0, getVikeConfig_js_1.isV1Design)(config, false)) && (0, fixServerAssets_js_1.fixServerAssets_isEnabled)();
135
140
  },
136
141
  load(id) {
137
142
  if (!(0, utils_js_1.isVirtualFileId)(id))
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.importBuild = void 0;
6
+ exports.set_constant_ASSETS_MAP = exports.importBuild = void 0;
7
7
  const plugin_js_1 = require("@brillout/vite-plugin-server-entry/plugin.js");
8
8
  const utils_js_1 = require("../../utils.js");
9
9
  const path_1 = __importDefault(require("path"));
@@ -26,11 +26,6 @@ function importBuild() {
26
26
  async configResolved(config_) {
27
27
  config = config_;
28
28
  configVike = await (0, getConfigVike_js_1.getConfigVike)(config);
29
- },
30
- async writeBundle(options, bundle) {
31
- if (!(0, utils_js_1.viteIsSSR)(config))
32
- return;
33
- await replace_ASSETS_MAP(options, bundle);
34
29
  }
35
30
  },
36
31
  ...(0, plugin_js_1.serverEntryPlugin)({
@@ -64,7 +59,8 @@ function getEntryCode(config, configVike) {
64
59
  ].join('\n');
65
60
  return importerCode;
66
61
  }
67
- async function replace_ASSETS_MAP(options, bundle) {
62
+ /** Set the value of the ASSETS_MAP constant inside dist/server/entry.js (or dist/server/index.js) */
63
+ async function set_constant_ASSETS_MAP(options, bundle) {
68
64
  const { dir } = options;
69
65
  (0, utils_js_1.assert)(dir);
70
66
  // This will probably fail with @vitejs/plugin-legacy
@@ -80,6 +76,7 @@ async function replace_ASSETS_MAP(options, bundle) {
80
76
  (0, utils_js_1.assert)(serverEntryFileContentPatched !== serverEntryFileContent);
81
77
  await promises_1.default.writeFile(serverEntryFilePath, serverEntryFileContentPatched);
82
78
  }
79
+ exports.set_constant_ASSETS_MAP = set_constant_ASSETS_MAP;
83
80
  function getImportPath(config) {
84
81
  // We resolve filePathAbsolute even if we don't use it: we use require.resolve() as an assertion that the relative path is correct
85
82
  const filePathAbsolute = (0, utils_js_1.toPosixPath)(
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isVikeConfigFile = exports.vikeConfigDependencies = exports.reloadVikeConfig = exports.getVikeConfig = void 0;
6
+ exports.isV1Design = exports.isVikeConfigFile = exports.vikeConfigDependencies = exports.reloadVikeConfig = exports.getVikeConfig = void 0;
7
7
  const utils_js_1 = require("../../../utils.js");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const configDefinitionsBuiltIn_js_1 = require("./getVikeConfig/configDefinitionsBuiltIn.js");
@@ -75,6 +75,11 @@ async function getVikeConfig(config, isDev, tolerateInvalidConfig = false, exten
75
75
  return await vikeConfigPromise;
76
76
  }
77
77
  exports.getVikeConfig = getVikeConfig;
78
+ async function isV1Design(config, isDev) {
79
+ const isV1Design = (await getVikeConfig(config, isDev)).pageConfigs.length > 0;
80
+ return isV1Design;
81
+ }
82
+ exports.isV1Design = isV1Design;
78
83
  async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
79
84
  const plusFiles = await findPlusFiles(userRootDir, outDirRoot, isDev, extensions);
80
85
  const configFiles = [];
@@ -12,6 +12,7 @@ const isRuntimeEnvMatch_js_1 = require("./isRuntimeEnvMatch.js");
12
12
  const serializeConfigValue_js_1 = require("../../../../../shared/page-configs/serialize/serializeConfigValue.js");
13
13
  const getConfigVike_js_1 = require("../../../../shared/getConfigVike.js");
14
14
  const getConfigValuesSerialized_js_1 = require("./getConfigValuesSerialized.js");
15
+ const fixServerAssets_js_1 = require("../../buildConfig/fixServerAssets.js");
15
16
  async function getVirtualFilePageConfigValuesAll(id, isDev, config) {
16
17
  const result = (0, virtualFilePageConfigValuesAll_js_1.isVirtualFileIdPageConfigValuesAll)(id);
17
18
  (0, utils_js_1.assert)(result);
@@ -45,7 +46,7 @@ function getLoadConfigValuesAll(pageConfig, isForClientSide, pageId, includeAsse
45
46
  isClientRouting
46
47
  })));
47
48
  lines.push('};');
48
- if (includeAssetsImportedByServer && isForClientSide && !isDev) {
49
+ if (!(0, fixServerAssets_js_1.fixServerAssets_isEnabled)() && includeAssetsImportedByServer && isForClientSide && !isDev) {
49
50
  importStatements.push(`import '${(0, extractAssetsQuery_js_1.extractAssetsAddQuery)((0, virtualFilePageConfigValuesAll_js_1.getVirtualFileIdPageConfigValuesAll)(pageId, false))}'`);
50
51
  }
51
52
  const code = [...importStatements, ...lines].join('\n');
@@ -41,3 +41,4 @@ __exportStar(require("../../utils/deepEqual.js"), exports);
41
41
  __exportStar(require("../../utils/assertKeys.js"), exports);
42
42
  __exportStar(require("../../utils/injectRollupInputs.js"), exports);
43
43
  __exportStar(require("../../utils/humanizeTime.js"), exports);
44
+ __exportStar(require("../../utils/pLimit.js"), exports);
@@ -19,6 +19,44 @@ function getHttpResponseBody(htmlRender, renderHook) {
19
19
  exports.getHttpResponseBody = getHttpResponseBody;
20
20
  function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
21
21
  return {
22
+ pipe(writable) {
23
+ const getErrMsgMixingStreamTypes = (writableType) => `The ${getErrMsgBody(htmlRender, renderHook)} while a ${writableType} was passed to pageContext.httpResponse.pipe() which is contradictory. You cannot mix a Web Stream with a Node.js Stream.`;
24
+ if ((0, stream_js_1.isStreamWritableWeb)(writable)) {
25
+ const success = (0, stream_js_1.pipeToStreamWritableWeb)(htmlRender, writable);
26
+ if (success) {
27
+ return;
28
+ }
29
+ else {
30
+ (0, utils_js_1.assert)((0, stream_js_1.isStreamReadableNode)(htmlRender) || (0, stream_js_1.isStreamPipeNode)(htmlRender));
31
+ (0, utils_js_1.assertUsage)(false, getErrMsgMixingStreamTypes('Web Writable'));
32
+ }
33
+ }
34
+ if ((0, stream_js_1.isStreamWritableNode)(writable)) {
35
+ const success = (0, stream_js_1.pipeToStreamWritableNode)(htmlRender, writable);
36
+ if (success) {
37
+ return;
38
+ }
39
+ else {
40
+ (0, utils_js_1.assert)((0, stream_js_1.isStreamReadableWeb)(htmlRender) || (0, stream_js_1.isStreamPipeWeb)(htmlRender));
41
+ (0, utils_js_1.assertUsage)(false, getErrMsgMixingStreamTypes('Node.js Writable'));
42
+ }
43
+ }
44
+ (0, utils_js_1.assertUsage)(false, `The argument ${picocolors_1.default.cyan('writable')} passed to ${picocolors_1.default.cyan('pageContext.httpResponse.pipe(writable)')} doesn't seem to be ${(0, stream_js_1.getStreamName)('writable', 'web')} nor ${(0, stream_js_1.getStreamName)('writable', 'node')}.`);
45
+ },
46
+ getReadableWebStream() {
47
+ const webStream = (0, stream_js_1.getStreamReadableWeb)(htmlRender);
48
+ if (webStream === null) {
49
+ (0, utils_js_1.assertUsage)(false, getErrMsg(htmlRender, renderHook, 'getReadableWebStream()', getFixMsg('readable', 'web')));
50
+ }
51
+ return webStream;
52
+ },
53
+ async getReadableNodeStream() {
54
+ const nodeStream = await (0, stream_js_1.getStreamReadableNode)(htmlRender);
55
+ if (nodeStream === null) {
56
+ (0, utils_js_1.assertUsage)(false, getErrMsg(htmlRender, renderHook, 'getReadableNodeStream()', getFixMsg('readable', 'node')));
57
+ }
58
+ return nodeStream;
59
+ },
22
60
  async getBody() {
23
61
  const body = await (0, renderHtml_js_1.getHtmlString)(htmlRender);
24
62
  return body;
@@ -43,20 +81,6 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
43
81
  }
44
82
  return webStream;
45
83
  },
46
- async getReadableNodeStream() {
47
- const nodeStream = await (0, stream_js_1.getStreamReadableNode)(htmlRender);
48
- if (nodeStream === null) {
49
- (0, utils_js_1.assertUsage)(false, getErrMsg(htmlRender, renderHook, 'getReadableNodeStream()', getFixMsg('readable', 'node')));
50
- }
51
- return nodeStream;
52
- },
53
- getReadableWebStream() {
54
- const webStream = (0, stream_js_1.getStreamReadableWeb)(htmlRender);
55
- if (webStream === null) {
56
- (0, utils_js_1.assertUsage)(false, getErrMsg(htmlRender, renderHook, 'getReadableWebStream()', getFixMsg('readable', 'web')));
57
- }
58
- return webStream;
59
- },
60
84
  // TODO/v1-release: remove
61
85
  pipeToWebWritable(writable) {
62
86
  (0, utils_js_1.assertWarning)(false, '`pageContext.httpResponse.pipeToWebWritable(res)` is outdated, use `pageContext.httpResponse.pipe(res)` instead. ' +
@@ -74,30 +98,6 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
74
98
  if (!success) {
75
99
  (0, utils_js_1.assertUsage)(false, getErrMsg(htmlRender, renderHook, 'pipeToNodeWritable()'));
76
100
  }
77
- },
78
- pipe(writable) {
79
- const getErrMsgMixingStreamTypes = (writableType) => `The ${getErrMsgBody(htmlRender, renderHook)} while a ${writableType} was passed to pageContext.httpResponse.pipe() which is contradictory. You cannot mix a Web Stream with a Node.js Stream.`;
80
- if ((0, stream_js_1.isStreamWritableWeb)(writable)) {
81
- const success = (0, stream_js_1.pipeToStreamWritableWeb)(htmlRender, writable);
82
- if (success) {
83
- return;
84
- }
85
- else {
86
- (0, utils_js_1.assert)((0, stream_js_1.isStreamReadableNode)(htmlRender) || (0, stream_js_1.isStreamPipeNode)(htmlRender));
87
- (0, utils_js_1.assertUsage)(false, getErrMsgMixingStreamTypes('Web Writable'));
88
- }
89
- }
90
- if ((0, stream_js_1.isStreamWritableNode)(writable)) {
91
- const success = (0, stream_js_1.pipeToStreamWritableNode)(htmlRender, writable);
92
- if (success) {
93
- return;
94
- }
95
- else {
96
- (0, utils_js_1.assert)((0, stream_js_1.isStreamReadableWeb)(htmlRender) || (0, stream_js_1.isStreamPipeWeb)(htmlRender));
97
- (0, utils_js_1.assertUsage)(false, getErrMsgMixingStreamTypes('Node.js Writable'));
98
- }
99
- }
100
- (0, utils_js_1.assertUsage)(false, `The argument ${picocolors_1.default.cyan('writable')} passed to ${picocolors_1.default.cyan('pageContext.httpResponse.pipe(writable)')} doesn't seem to be ${(0, stream_js_1.getStreamName)('writable', 'web')} nor ${(0, stream_js_1.getStreamName)('writable', 'node')}.`);
101
101
  }
102
102
  };
103
103
  function getFixMsg(type, standard) {
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = exports.projectInfo = void 0;
4
4
  const assertSingleInstance_js_1 = require("./assertSingleInstance.js");
5
- const PROJECT_VERSION = '0.4.160-commit-937d8d5';
5
+ const PROJECT_VERSION = '0.4.160-commit-d574f51';
6
6
  exports.PROJECT_VERSION = PROJECT_VERSION;
7
7
  const projectInfo = {
8
8
  projectName: 'Vike',
@@ -1,6 +1,6 @@
1
1
  export { navigate, reload } from './navigate.js';
2
2
  export { prefetch } from './prefetch.js';
3
- export { PROJECT_VERSION } from './utils.js';
3
+ export { PROJECT_VERSION as version } from './utils.js';
4
4
  import type { PageContextBuiltInClientWithClientRouting } from '../../shared/types.js';
5
5
  /** @deprecated
6
6
  * Replace:
@@ -5,4 +5,4 @@
5
5
  // Use package.json#exports to make the imports isomorphic.
6
6
  export { navigate, reload } from './navigate.js';
7
7
  export { prefetch } from './prefetch.js';
8
- export { PROJECT_VERSION } from './utils.js';
8
+ export { PROJECT_VERSION as version } from './utils.js';
@@ -1,7 +1,8 @@
1
1
  import { cac } from 'cac';
2
2
  import { resolve } from 'path';
3
3
  import { runPrerenderFromCLI, runPrerender_forceExit } from '../prerender/runPrerender.js';
4
- import { projectInfo, assertUsage } from './utils.js';
4
+ import { projectInfo, assertUsage, assertWarning } from './utils.js';
5
+ import pc from '@brillout/picocolors';
5
6
  const cli = cac(projectInfo.projectName);
6
7
  cli
7
8
  .command('prerender', 'Pre-render the HTML of your pages', { allowUnknownOptions: true })
@@ -28,6 +29,7 @@ function assertOptions() {
28
29
  '--outDir',
29
30
  '--configFile'
30
31
  ].includes(option), 'Unknown option: ' + option);
32
+ assertWarning(false, `You set ${pc.cyan(option)}, but passing options to ${pc.cyan('$ vike prerender')} is deprecated: use the config file instead. See https://vike.dev/command-prerender.`, { onlyOnce: true });
31
33
  });
32
34
  }
33
35
  // Listen to unknown commands
@@ -0,0 +1,13 @@
1
+ export { fixServerAssets };
2
+ export { fixServerAssets_isEnabled };
3
+ import { ViteManifest } from '../../../shared/ViteManifest.js';
4
+ import { OutDirs } from '../../utils.js';
5
+ /**
6
+ * true => use workaround config.build.ssrEmitAssets
7
+ * false => use workaround extractAssets plugin
8
+ *
9
+ * Only used by V1 design.
10
+ */
11
+ declare function fixServerAssets_isEnabled(): boolean;
12
+ /** https://github.com/vikejs/vike/issues/1339 */
13
+ declare function fixServerAssets(outDirs: OutDirs): Promise<ViteManifest>;
@@ -0,0 +1,142 @@
1
+ export { fixServerAssets };
2
+ export { fixServerAssets_isEnabled };
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { existsSync } from 'fs';
6
+ import { assert, pLimit, unique } from '../../utils.js';
7
+ import { isVirtualFileIdPageConfigValuesAll } from '../../../shared/virtual-files/virtualFilePageConfigValuesAll.js';
8
+ import { manifestTempFile } from '../buildConfig.js';
9
+ /**
10
+ * true => use workaround config.build.ssrEmitAssets
11
+ * false => use workaround extractAssets plugin
12
+ *
13
+ * Only used by V1 design.
14
+ */
15
+ function fixServerAssets_isEnabled() {
16
+ // We currently apply the workaround iff V1 design.
17
+ // Shall we allow the user to toggle between the two workarounds? E.g. based on https://vike.dev/includeAssetsImportedByServer.
18
+ return true;
19
+ }
20
+ /** https://github.com/vikejs/vike/issues/1339 */
21
+ async function fixServerAssets(outDirs) {
22
+ const clientManifest = await loadManifest(outDirs.outDirClient);
23
+ const serverManifest = await loadManifest(outDirs.outDirServer);
24
+ const { clientManifestMod, filesToCopy } = addServerAssets(clientManifest, serverManifest);
25
+ await copyAssets(filesToCopy, outDirs);
26
+ return clientManifestMod;
27
+ }
28
+ async function loadManifest(outDir) {
29
+ const manifestFilePath = path.posix.join(outDir, manifestTempFile);
30
+ const manifestFileContent = await fs.readFile(manifestFilePath, 'utf-8');
31
+ assert(manifestFileContent);
32
+ const manifest = JSON.parse(manifestFileContent);
33
+ assert(manifest);
34
+ return manifest;
35
+ }
36
+ async function copyAssets(filesToCopy, { outDirClient, outDirServer }) {
37
+ const assetsDirServer = path.posix.join(outDirServer, 'assets');
38
+ if (!filesToCopy.length)
39
+ return;
40
+ assert(existsSync(assetsDirServer));
41
+ const concurrencyLimit = pLimit(10);
42
+ await Promise.all(filesToCopy.map((file) => concurrencyLimit(() => fs.cp(path.posix.join(outDirServer, file), path.posix.join(outDirClient, file), {
43
+ recursive: true
44
+ }))));
45
+ await fs.rm(assetsDirServer, { recursive: true });
46
+ }
47
+ // Add serverManifest resources to clientManifest
48
+ function addServerAssets(clientManifest, serverManifest) {
49
+ var _a, _b;
50
+ const entriesClient = new Map();
51
+ const entriesServer = new Map();
52
+ for (const [key, entry] of Object.entries(clientManifest)) {
53
+ const pageId = getPageId(key);
54
+ if (!pageId)
55
+ continue;
56
+ const resources = collectResources(entry, clientManifest);
57
+ assert(!entriesClient.has(pageId));
58
+ entriesClient.set(pageId, { key, ...resources });
59
+ }
60
+ for (const [key, entry] of Object.entries(serverManifest)) {
61
+ const pageId = getPageId(key);
62
+ if (!pageId)
63
+ continue;
64
+ const resources = collectResources(entry, serverManifest);
65
+ assert(!entriesServer.has(pageId));
66
+ entriesServer.set(pageId, resources);
67
+ }
68
+ let filesToCopy = [];
69
+ for (const [pageId, entryClient] of entriesClient.entries()) {
70
+ const cssToAdd = [];
71
+ const assetsToAdd = [];
72
+ const entryServer = entriesServer.get(pageId);
73
+ if (entryServer) {
74
+ cssToAdd.push(...entryServer.css
75
+ .filter((cssServer) => !entryClient.css.some((cssClient) => cssServer.hash === cssClient.hash))
76
+ .map((css) => css.src));
77
+ assetsToAdd.push(...entryServer.assets
78
+ .filter((assertServer) => !entryClient.assets.some((assetClient) => assertServer.hash === assetClient.hash))
79
+ .map((asset) => asset.src));
80
+ }
81
+ const { key } = entryClient;
82
+ if (cssToAdd.length) {
83
+ filesToCopy.push(...cssToAdd);
84
+ (_a = clientManifest[key]).css ?? (_a.css = []);
85
+ clientManifest[key].css?.push(...cssToAdd);
86
+ }
87
+ if (assetsToAdd.length) {
88
+ filesToCopy.push(...assetsToAdd);
89
+ (_b = clientManifest[key]).assets ?? (_b.assets = []);
90
+ clientManifest[key].assets?.push(...assetsToAdd);
91
+ }
92
+ }
93
+ const clientManifestMod = clientManifest;
94
+ filesToCopy = unique(filesToCopy);
95
+ return { clientManifestMod, filesToCopy };
96
+ }
97
+ function getPageId(key) {
98
+ // Normalize from:
99
+ // ../../virtual:vike:pageConfigValuesAll:client:/pages/index
100
+ // to:
101
+ // virtual:vike:pageConfigValuesAll:client:/pages/index
102
+ // (This seems to be needed only for vitest tests that use Vite's build() API with an inline config.)
103
+ key = key.substring(key.indexOf('virtual:vike'));
104
+ const result = isVirtualFileIdPageConfigValuesAll(key);
105
+ return result && result.pageId;
106
+ }
107
+ function collectResources(entryRoot, manifest) {
108
+ const css = [];
109
+ const assets = [];
110
+ const entries = new Set([entryRoot]);
111
+ for (const entry of entries) {
112
+ for (const entryImport of entry.imports ?? []) {
113
+ entries.add(manifest[entryImport]);
114
+ }
115
+ const entryCss = entry.css ?? [];
116
+ if (entry.file.endsWith('.css'))
117
+ entryCss.push(entry.file);
118
+ for (const src of entryCss) {
119
+ const hash = getHash(src);
120
+ css.push({ src, hash });
121
+ }
122
+ const entryAssets = entry.assets ?? [];
123
+ for (const src of entryAssets) {
124
+ const hash = getHash(src);
125
+ assets.push({ src, hash });
126
+ }
127
+ }
128
+ return { css, assets };
129
+ }
130
+ // Use the hash of resources to determine whether they are equal. We need this, otherwise we get:
131
+ // ```html
132
+ // <head>
133
+ // <link rel="stylesheet" type="text/css" href="/assets/static/onRenderClient.2j6TxKIB.css">
134
+ // <link rel="stylesheet" type="text/css" href="/assets/static/onRenderHtml.2j6TxKIB.css">
135
+ // </head>
136
+ // ```
137
+ function getHash(src) {
138
+ // src is guarenteed to end with `.[hash][extname]`, see distFileNames.ts
139
+ const hash = src.split('.').at(-2);
140
+ assert(hash);
141
+ return hash;
142
+ }
@@ -1,8 +1,10 @@
1
1
  export { buildConfig };
2
2
  export { assertRollupInput };
3
3
  export { analyzeClientEntries };
4
+ export { manifestTempFile };
4
5
  import type { ResolvedConfig, Plugin } from 'vite';
5
6
  import type { PageConfigBuildTime } from '../../../shared/page-configs/PageConfig.js';
7
+ declare const manifestTempFile = "_temp_manifest.json";
6
8
  declare function buildConfig(): Plugin;
7
9
  declare function analyzeClientEntries(pageConfigs: PageConfigBuildTime[], config: ResolvedConfig): {
8
10
  hasClientRouting: boolean;
@@ -1,8 +1,9 @@
1
1
  export { buildConfig };
2
2
  export { assertRollupInput };
3
3
  export { analyzeClientEntries };
4
- import { assert, resolveOutDir, viteIsSSR, getFilePathAbsolute, addOnBeforeLogHook, removeFileExtention, unique, assertPosixPath, assertUsage, injectRollupInputs, normalizeRollupInput, assertNodeEnvIsNotDev } from '../utils.js';
5
- import { getVikeConfig } from './importUserCode/v1-design/getVikeConfig.js';
4
+ export { manifestTempFile };
5
+ import { assert, resolveOutDir, viteIsSSR, getFilePathAbsolute, addOnBeforeLogHook, removeFileExtention, unique, assertPosixPath, assertUsage, injectRollupInputs, normalizeRollupInput, assertNodeEnvIsNotDev, getOutDirs } from '../utils.js';
6
+ import { getVikeConfig, isV1Design } from './importUserCode/v1-design/getVikeConfig.js';
6
7
  import { getConfigValue } from '../../../shared/page-configs/helpers.js';
7
8
  import { findPageFiles } from '../shared/findPageFiles.js';
8
9
  import { getConfigVike } from '../../shared/getConfigVike.js';
@@ -12,12 +13,16 @@ import { createRequire } from 'module';
12
13
  import { getClientEntryFilePath } from '../../shared/getClientEntryFilePath.js';
13
14
  import fs from 'fs/promises';
14
15
  import path from 'path';
16
+ import { fixServerAssets, fixServerAssets_isEnabled } from './buildConfig/fixServerAssets.js';
17
+ import { set_constant_ASSETS_MAP } from './importBuild/index.js';
15
18
  // @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
16
19
  const importMetaUrl = import.meta.url;
17
20
  const require_ = createRequire(importMetaUrl);
18
21
  const manifestTempFile = '_temp_manifest.json';
19
22
  function buildConfig() {
20
- let generateManifest;
23
+ let isServerAssetsFixEnabled;
24
+ let isSsrBuild;
25
+ let outDirs;
21
26
  return {
22
27
  name: 'vike:buildConfig',
23
28
  apply: 'build',
@@ -31,16 +36,26 @@ function buildConfig() {
31
36
  assert(Object.keys(entries).length > 0);
32
37
  config.build.rollupOptions.input = injectRollupInputs(entries, config);
33
38
  addLogHook();
39
+ outDirs = getOutDirs(config);
40
+ {
41
+ isServerAssetsFixEnabled = (await isV1Design(config, false)) && fixServerAssets_isEnabled();
42
+ if (isServerAssetsFixEnabled) {
43
+ // https://github.com/vikejs/vike/issues/1339
44
+ config.build.ssrEmitAssets = true;
45
+ // Required if `ssrEmitAssets: true`, see https://github.com/vitejs/vite/pull/11430#issuecomment-1454800934
46
+ config.build.cssMinify = 'esbuild';
47
+ }
48
+ }
34
49
  }
35
50
  },
36
51
  config(config) {
37
52
  assertNodeEnv();
38
- generateManifest = !viteIsSSR(config);
53
+ isSsrBuild = viteIsSSR(config);
39
54
  return {
40
55
  build: {
41
56
  outDir: resolveOutDir(config),
42
- manifest: generateManifest ? manifestTempFile : false,
43
- copyPublicDir: !viteIsSSR(config)
57
+ manifest: manifestTempFile,
58
+ copyPublicDir: !isSsrBuild
44
59
  }
45
60
  };
46
61
  },
@@ -48,20 +63,23 @@ function buildConfig() {
48
63
  assertNodeEnv();
49
64
  },
50
65
  async writeBundle(options, bundle) {
51
- assertNodeEnv();
52
- const manifestEntry = bundle[manifestTempFile];
53
- /* Fails with @vitejs/plugin-legacy because writeBundle() is called twice during the client build (once for normal client assets and a second time for legacy assets), see reproduction at https://github.com/vikejs/vike/issues/1154
54
- assert(generateManifest === !!manifestEntry)
55
- */
56
- if (manifestEntry) {
57
- const { dir } = options;
58
- assert(dir);
59
- const manifestFilePathOld = path.join(dir, manifestEntry.fileName);
66
+ if (isSsrBuild) {
60
67
  // Ideally we'd move dist/_temp_manifest.json to dist/server/client-assets.json instead of dist/assets.json
61
68
  // - But we can't because there is no guarentee whether dist/server/ is generated before or after dist/client/ (generating dist/server/ after dist/client/ erases dist/server/client-assets.json)
62
69
  // - We'll able to do so once we replace `$ vite build` with `$ vike build`
63
- const manifestFilePathNew = path.join(dir, '..', 'assets.json');
64
- await fs.rename(manifestFilePathOld, manifestFilePathNew);
70
+ const assetsJsonFilePath = path.posix.join(outDirs.outDirRoot, 'assets.json');
71
+ const clientManifestFilePath = path.posix.join(outDirs.outDirClient, manifestTempFile);
72
+ const serverManifestFilePath = path.posix.join(outDirs.outDirServer, manifestTempFile);
73
+ if (!isServerAssetsFixEnabled) {
74
+ await fs.copyFile(clientManifestFilePath, assetsJsonFilePath);
75
+ }
76
+ else {
77
+ const clientManifestMod = await fixServerAssets(outDirs);
78
+ await fs.writeFile(assetsJsonFilePath, JSON.stringify(clientManifestMod, null, 2), 'utf-8');
79
+ }
80
+ await fs.rm(clientManifestFilePath);
81
+ await fs.rm(serverManifestFilePath);
82
+ await set_constant_ASSETS_MAP(options, bundle);
65
83
  }
66
84
  }
67
85
  };
@@ -19,9 +19,17 @@ function distFileNames() {
19
19
  if (!('chunkFileNames' in rollupOutput)) {
20
20
  rollupOutput.chunkFileNames = (chunkInfo) => getChunkFileName(chunkInfo, config);
21
21
  }
22
- if (!('assertUsage' in rollupOutput)) {
22
+ if (!('assetFileNames' in rollupOutput)) {
23
23
  rollupOutput.assetFileNames = (chunkInfo) => getAssetFileName(chunkInfo, config);
24
24
  }
25
+ else {
26
+ // If a user needs this:
27
+ // - assertUsage() that the naming provided by the user ends with `.[hash][extname]`
28
+ // - It's needed for getHash() of fixServerAssets()
29
+ // - Asset URLs should always contain a hash: it's paramount for caching assets.
30
+ // - If rollupOutput.assetFileNames is a function then use a wrapper function to apply the assertUsage()
31
+ assertUsage(false, "Setting config.build.rollupOptions.output.assetFileNames is currently forbidden. (Contact a maintainer if you need this as it's possible to support this.)");
32
+ }
25
33
  });
26
34
  }
27
35
  };
@@ -1,6 +1,6 @@
1
- // Alternative: use `ssrEmitAssets: true`
2
- // - See https://github.com/vitejs/vite/pull/11430
3
- // This plugin makes client-side bundles include the CSS imports living in server-side-only code.
1
+ // Remove this workaround if the other workaround config.build.ssrEmitAssets turns out to be reliable.
2
+ // - Remove this file then revert this commit: https://github.com/vikejs/vike/commit/805a18974f13420a78fcc30fdd676696e405c3ca
3
+ // Workaround to make client-side bundles include the CSS imports living in server-side-only code.
4
4
  // - This is needed for HTML-only pages, and React Server Components.
5
5
  // - We recommend using the debug flag to get an idea of how this plugin works: `$ DEBUG=vike:extractAssets pnpm exec vite build`. Then have a look at `dist/client/manifest.json` and see how `.page.server.js` entries have zero JavaScript but only CSS.
6
6
  // - This appraoch supports import path aliases `vite.config.js#resolve.alias` https://vitejs.dev/config/#resolve-alias
@@ -9,10 +9,12 @@ export { extractAssetsRE };
9
9
  import { viteIsSSR_options, assert, assertPosixPath, styleFileRE, createDebugger, isDebugEnabled, isScriptFile, resolveVirtualFileId, isVirtualFileId, getVirtualFileId, assertUsage } from '../utils.js';
10
10
  import { extractAssetsAddQuery } from '../../shared/extractAssetsQuery.js';
11
11
  import { getConfigVike } from '../../shared/getConfigVike.js';
12
+ import { isV1Design } from './importUserCode/v1-design/getVikeConfig.js';
12
13
  import { isAsset } from '../shared/isAsset.js';
13
14
  import { getImportStatements } from '../shared/parseEsModule.js';
14
15
  import { removeSourceMap } from '../shared/removeSourceMap.js';
15
16
  import pc from '@brillout/picocolors';
17
+ import { fixServerAssets_isEnabled } from './buildConfig/fixServerAssets.js';
16
18
  const extractAssetsRE = /(\?|&)extractAssets(?:&|$)/;
17
19
  const rawRE = /(\?|&)raw(?:&|$)/;
18
20
  const urlRE = /(\?|&)url(?:&|$)/;
@@ -23,6 +25,7 @@ const debugEnabled = isDebugEnabled(debugNamespace);
23
25
  function extractAssetsPlugin() {
24
26
  let config;
25
27
  let configVike;
28
+ let isServerAssetsFixEnabled;
26
29
  return [
27
30
  // This plugin removes all JavaScript from server-side only code, so that only CSS imports remains. (And also satic files imports e.g. `import logoURL from './logo.svg.js'`).
28
31
  {
@@ -34,6 +37,7 @@ function extractAssetsPlugin() {
34
37
  if (!extractAssetsRE.test(id)) {
35
38
  return;
36
39
  }
40
+ assert(!isServerAssetsFixEnabled);
37
41
  assert(configVike.includeAssetsImportedByServer);
38
42
  assert(!viteIsSSR_options(options));
39
43
  const importStatements = await getImportStatements(src);
@@ -131,6 +135,7 @@ function extractAssetsPlugin() {
131
135
  async configResolved(config_) {
132
136
  configVike = await getConfigVike(config_);
133
137
  config = config_;
138
+ isServerAssetsFixEnabled = (await isV1Design(config, false)) && fixServerAssets_isEnabled();
134
139
  },
135
140
  load(id) {
136
141
  if (!isVirtualFileId(id))
@@ -1,3 +1,8 @@
1
1
  export { importBuild };
2
- import type { Plugin } from 'vite';
2
+ export { set_constant_ASSETS_MAP };
3
+ import type { Plugin, Rollup } from 'vite';
4
+ type Bundle = Rollup.OutputBundle;
5
+ type Options = Rollup.NormalizedOutputOptions;
3
6
  declare function importBuild(): Plugin[];
7
+ /** Set the value of the ASSETS_MAP constant inside dist/server/entry.js (or dist/server/index.js) */
8
+ declare function set_constant_ASSETS_MAP(options: Options, bundle: Bundle): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  export { importBuild };
2
+ export { set_constant_ASSETS_MAP };
2
3
  import { serverEntryPlugin, findServerEntry } from '@brillout/vite-plugin-server-entry/plugin.js';
3
- import { assert, getOutDirs, toPosixPath, viteIsSSR } from '../../utils.js';
4
+ import { assert, getOutDirs, toPosixPath } from '../../utils.js';
4
5
  import path from 'path';
5
6
  import { createRequire } from 'module';
6
7
  import { getConfigVike } from '../../../shared/getConfigVike.js';
@@ -21,11 +22,6 @@ function importBuild() {
21
22
  async configResolved(config_) {
22
23
  config = config_;
23
24
  configVike = await getConfigVike(config);
24
- },
25
- async writeBundle(options, bundle) {
26
- if (!viteIsSSR(config))
27
- return;
28
- await replace_ASSETS_MAP(options, bundle);
29
25
  }
30
26
  },
31
27
  ...serverEntryPlugin({
@@ -58,7 +54,8 @@ function getEntryCode(config, configVike) {
58
54
  ].join('\n');
59
55
  return importerCode;
60
56
  }
61
- async function replace_ASSETS_MAP(options, bundle) {
57
+ /** Set the value of the ASSETS_MAP constant inside dist/server/entry.js (or dist/server/index.js) */
58
+ async function set_constant_ASSETS_MAP(options, bundle) {
62
59
  const { dir } = options;
63
60
  assert(dir);
64
61
  // This will probably fail with @vitejs/plugin-legacy
@@ -2,6 +2,7 @@ export { getVikeConfig };
2
2
  export { reloadVikeConfig };
3
3
  export { vikeConfigDependencies };
4
4
  export { isVikeConfigFile };
5
+ export { isV1Design };
5
6
  export type { InterfaceValueFile };
6
7
  import type { PageConfigGlobalBuildTime, PageConfigBuildTime, FilePathResolved } from '../../../../../shared/page-configs/PageConfig.js';
7
8
  import type { ExtensionResolved } from '../../../../../shared/ConfigVike.js';
@@ -28,4 +29,5 @@ type VikeConfig = {
28
29
  declare const vikeConfigDependencies: Set<string>;
29
30
  declare function reloadVikeConfig(userRootDir: string, outDirRoot: string, extensions: ExtensionResolved[]): void;
30
31
  declare function getVikeConfig(config: ResolvedConfig, isDev: boolean, tolerateInvalidConfig?: boolean, extensions?: ExtensionResolved[]): Promise<VikeConfig>;
32
+ declare function isV1Design(config: ResolvedConfig, isDev: boolean): Promise<boolean>;
31
33
  declare function isVikeConfigFile(filePath: string): boolean;
@@ -2,6 +2,7 @@ export { getVikeConfig };
2
2
  export { reloadVikeConfig };
3
3
  export { vikeConfigDependencies };
4
4
  export { isVikeConfigFile };
5
+ export { isV1Design };
5
6
  import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEntries, hasProp, arrayIncludes, assertIsNotProductionRuntime, getMostSimilar, joinEnglish, lowerFirst, mergeCumulativeValues, getOutDirs, assertKeys, objectKeys, objectFromEntries, makeFirst, isNpmPackageImport, reverse } from '../../../utils.js';
6
7
  import path from 'path';
7
8
  import { configDefinitionsBuiltIn, configDefinitionsBuiltInGlobal } from './getVikeConfig/configDefinitionsBuiltIn.js';
@@ -70,6 +71,10 @@ async function getVikeConfig(config, isDev, tolerateInvalidConfig = false, exten
70
71
  }
71
72
  return await vikeConfigPromise;
72
73
  }
74
+ async function isV1Design(config, isDev) {
75
+ const isV1Design = (await getVikeConfig(config, isDev)).pageConfigs.length > 0;
76
+ return isV1Design;
77
+ }
73
78
  async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
74
79
  const plusFiles = await findPlusFiles(userRootDir, outDirRoot, isDev, extensions);
75
80
  const configFiles = [];
@@ -10,6 +10,7 @@ import { isRuntimeEnvMatch } from './isRuntimeEnvMatch.js';
10
10
  import { serializeConfigValueImported } from '../../../../../shared/page-configs/serialize/serializeConfigValue.js';
11
11
  import { getConfigVike } from '../../../../shared/getConfigVike.js';
12
12
  import { getConfigValuesSerialized } from './getConfigValuesSerialized.js';
13
+ import { fixServerAssets_isEnabled } from '../../buildConfig/fixServerAssets.js';
13
14
  async function getVirtualFilePageConfigValuesAll(id, isDev, config) {
14
15
  const result = isVirtualFileIdPageConfigValuesAll(id);
15
16
  assert(result);
@@ -42,7 +43,7 @@ function getLoadConfigValuesAll(pageConfig, isForClientSide, pageId, includeAsse
42
43
  isClientRouting
43
44
  })));
44
45
  lines.push('};');
45
- if (includeAssetsImportedByServer && isForClientSide && !isDev) {
46
+ if (!fixServerAssets_isEnabled() && includeAssetsImportedByServer && isForClientSide && !isDev) {
46
47
  importStatements.push(`import '${extractAssetsAddQuery(getVirtualFileIdPageConfigValuesAll(pageId, false))}'`);
47
48
  }
48
49
  const code = [...importStatements, ...lines].join('\n');
@@ -19,3 +19,4 @@ export * from '../../utils/deepEqual.js';
19
19
  export * from '../../utils/assertKeys.js';
20
20
  export * from '../../utils/injectRollupInputs.js';
21
21
  export * from '../../utils/humanizeTime.js';
22
+ export * from '../../utils/pLimit.js';
@@ -25,3 +25,4 @@ export * from '../../utils/deepEqual.js';
25
25
  export * from '../../utils/assertKeys.js';
26
26
  export * from '../../utils/injectRollupInputs.js';
27
27
  export * from '../../utils/humanizeTime.js';
28
+ export * from '../../utils/pLimit.js';
@@ -7,9 +7,10 @@ import { type HtmlRender } from '../html/renderHtml.js';
7
7
  import type { RenderHook } from './executeOnRenderHtmlHook.js';
8
8
  type HttpResponseBody = {
9
9
  body: string;
10
- getBody: () => Promise<string>;
11
- getReadableWebStream: () => StreamReadableWeb;
12
10
  pipe: (writable: StreamWritableWeb | StreamWritableNode) => void;
11
+ getReadableWebStream: () => StreamReadableWeb;
12
+ getReadableNodeStream: () => Promise<StreamReadableNode>;
13
+ getBody: () => Promise<string>;
13
14
  /** @deprecated */
14
15
  getNodeStream: () => Promise<StreamReadableNode>;
15
16
  /** @deprecated */
@@ -21,12 +22,12 @@ type HttpResponseBody = {
21
22
  };
22
23
  declare function getHttpResponseBody(htmlRender: HtmlRender, renderHook: null | RenderHook): string;
23
24
  declare function getHttpResponseBodyStreamHandlers(htmlRender: HtmlRender, renderHook: null | RenderHook): {
25
+ pipe(writable: StreamWritableNode | StreamWritableWeb): void;
26
+ getReadableWebStream(): StreamReadableWeb;
27
+ getReadableNodeStream(): Promise<import("stream").Readable>;
24
28
  getBody(): Promise<string>;
25
29
  getNodeStream(): Promise<import("stream").Readable>;
26
30
  getWebStream(): StreamReadableWeb;
27
- getReadableNodeStream(): Promise<import("stream").Readable>;
28
- getReadableWebStream(): StreamReadableWeb;
29
31
  pipeToWebWritable(writable: StreamWritableWeb): void;
30
32
  pipeToNodeWritable(writable: StreamWritableNode): void;
31
- pipe(writable: StreamWritableNode | StreamWritableWeb): void;
32
33
  };
@@ -14,6 +14,44 @@ function getHttpResponseBody(htmlRender, renderHook) {
14
14
  }
15
15
  function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
16
16
  return {
17
+ pipe(writable) {
18
+ const getErrMsgMixingStreamTypes = (writableType) => `The ${getErrMsgBody(htmlRender, renderHook)} while a ${writableType} was passed to pageContext.httpResponse.pipe() which is contradictory. You cannot mix a Web Stream with a Node.js Stream.`;
19
+ if (isStreamWritableWeb(writable)) {
20
+ const success = pipeToStreamWritableWeb(htmlRender, writable);
21
+ if (success) {
22
+ return;
23
+ }
24
+ else {
25
+ assert(isStreamReadableNode(htmlRender) || isStreamPipeNode(htmlRender));
26
+ assertUsage(false, getErrMsgMixingStreamTypes('Web Writable'));
27
+ }
28
+ }
29
+ if (isStreamWritableNode(writable)) {
30
+ const success = pipeToStreamWritableNode(htmlRender, writable);
31
+ if (success) {
32
+ return;
33
+ }
34
+ else {
35
+ assert(isStreamReadableWeb(htmlRender) || isStreamPipeWeb(htmlRender));
36
+ assertUsage(false, getErrMsgMixingStreamTypes('Node.js Writable'));
37
+ }
38
+ }
39
+ assertUsage(false, `The argument ${pc.cyan('writable')} passed to ${pc.cyan('pageContext.httpResponse.pipe(writable)')} doesn't seem to be ${getStreamName('writable', 'web')} nor ${getStreamName('writable', 'node')}.`);
40
+ },
41
+ getReadableWebStream() {
42
+ const webStream = getStreamReadableWeb(htmlRender);
43
+ if (webStream === null) {
44
+ assertUsage(false, getErrMsg(htmlRender, renderHook, 'getReadableWebStream()', getFixMsg('readable', 'web')));
45
+ }
46
+ return webStream;
47
+ },
48
+ async getReadableNodeStream() {
49
+ const nodeStream = await getStreamReadableNode(htmlRender);
50
+ if (nodeStream === null) {
51
+ assertUsage(false, getErrMsg(htmlRender, renderHook, 'getReadableNodeStream()', getFixMsg('readable', 'node')));
52
+ }
53
+ return nodeStream;
54
+ },
17
55
  async getBody() {
18
56
  const body = await getHtmlString(htmlRender);
19
57
  return body;
@@ -38,20 +76,6 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
38
76
  }
39
77
  return webStream;
40
78
  },
41
- async getReadableNodeStream() {
42
- const nodeStream = await getStreamReadableNode(htmlRender);
43
- if (nodeStream === null) {
44
- assertUsage(false, getErrMsg(htmlRender, renderHook, 'getReadableNodeStream()', getFixMsg('readable', 'node')));
45
- }
46
- return nodeStream;
47
- },
48
- getReadableWebStream() {
49
- const webStream = getStreamReadableWeb(htmlRender);
50
- if (webStream === null) {
51
- assertUsage(false, getErrMsg(htmlRender, renderHook, 'getReadableWebStream()', getFixMsg('readable', 'web')));
52
- }
53
- return webStream;
54
- },
55
79
  // TODO/v1-release: remove
56
80
  pipeToWebWritable(writable) {
57
81
  assertWarning(false, '`pageContext.httpResponse.pipeToWebWritable(res)` is outdated, use `pageContext.httpResponse.pipe(res)` instead. ' +
@@ -69,30 +93,6 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
69
93
  if (!success) {
70
94
  assertUsage(false, getErrMsg(htmlRender, renderHook, 'pipeToNodeWritable()'));
71
95
  }
72
- },
73
- pipe(writable) {
74
- const getErrMsgMixingStreamTypes = (writableType) => `The ${getErrMsgBody(htmlRender, renderHook)} while a ${writableType} was passed to pageContext.httpResponse.pipe() which is contradictory. You cannot mix a Web Stream with a Node.js Stream.`;
75
- if (isStreamWritableWeb(writable)) {
76
- const success = pipeToStreamWritableWeb(htmlRender, writable);
77
- if (success) {
78
- return;
79
- }
80
- else {
81
- assert(isStreamReadableNode(htmlRender) || isStreamPipeNode(htmlRender));
82
- assertUsage(false, getErrMsgMixingStreamTypes('Web Writable'));
83
- }
84
- }
85
- if (isStreamWritableNode(writable)) {
86
- const success = pipeToStreamWritableNode(htmlRender, writable);
87
- if (success) {
88
- return;
89
- }
90
- else {
91
- assert(isStreamReadableWeb(htmlRender) || isStreamPipeWeb(htmlRender));
92
- assertUsage(false, getErrMsgMixingStreamTypes('Node.js Writable'));
93
- }
94
- }
95
- assertUsage(false, `The argument ${pc.cyan('writable')} passed to ${pc.cyan('pageContext.httpResponse.pipe(writable)')} doesn't seem to be ${getStreamName('writable', 'web')} nor ${getStreamName('writable', 'node')}.`);
96
96
  }
97
97
  };
98
98
  function getFixMsg(type, standard) {
@@ -1,5 +1,6 @@
1
1
  export { getOutDirs };
2
2
  export { resolveOutDir };
3
+ export type { OutDirs };
3
4
  import type { UserConfig, ResolvedConfig } from 'vite';
4
5
  type OutDirs = {
5
6
  /** Absolute path to `outDir` */
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- declare const PROJECT_VERSION: "0.4.160-commit-937d8d5";
3
+ declare const PROJECT_VERSION: "0.4.160-commit-d574f51";
4
4
  declare const projectInfo: {
5
5
  projectName: "Vike";
6
- projectVersion: "0.4.160-commit-937d8d5";
6
+ projectVersion: "0.4.160-commit-d574f51";
7
7
  };
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
3
  import { onProjectInfo } from './assertSingleInstance.js';
4
- const PROJECT_VERSION = '0.4.160-commit-937d8d5';
4
+ const PROJECT_VERSION = '0.4.160-commit-d574f51';
5
5
  const projectInfo = {
6
6
  projectName: 'Vike',
7
7
  projectVersion: PROJECT_VERSION
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.160-commit-937d8d5",
3
+ "version": "0.4.160-commit-d574f51",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",