vike 0.4.167 → 0.4.168-commit-ce94f5c

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 (29) hide show
  1. package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +1 -1
  2. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +9 -1
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +0 -8
  4. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveImportPath.js +14 -35
  5. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +121 -95
  6. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +27 -8
  7. package/dist/cjs/node/plugin/shared/getFilePath.js +6 -1
  8. package/dist/cjs/node/runtime/renderPage/analyzePage.js +1 -1
  9. package/dist/cjs/node/runtime/renderPage/logErrorHint.js +13 -1
  10. package/dist/cjs/utils/assertPathIsFilesystemAbsolute.js +3 -3
  11. package/dist/cjs/utils/projectInfo.js +1 -1
  12. package/dist/esm/client/client-routing-runtime/history.d.ts +1 -0
  13. package/dist/esm/client/client-routing-runtime/history.js +23 -19
  14. package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +1 -1
  15. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +9 -1
  16. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +1 -9
  17. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolveImportPath.js +14 -35
  18. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transformFileImports.d.ts +1 -1
  19. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.d.ts +2 -2
  20. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +121 -95
  21. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +28 -9
  22. package/dist/esm/node/plugin/shared/getFilePath.js +6 -1
  23. package/dist/esm/node/runtime/renderPage/analyzePage.js +1 -1
  24. package/dist/esm/node/runtime/renderPage/logErrorHint.js +13 -1
  25. package/dist/esm/shared/addUrlComputedProps.d.ts +2 -2
  26. package/dist/esm/utils/assertPathIsFilesystemAbsolute.js +3 -3
  27. package/dist/esm/utils/projectInfo.d.ts +2 -2
  28. package/dist/esm/utils/projectInfo.js +1 -1
  29. package/package.json +2 -2
@@ -1,6 +1,5 @@
1
1
  export { initHistoryState, getHistoryState, pushHistory, saveScrollPosition, monkeyPatchHistoryPushState };
2
- import { assert, assertUsage, getGlobalObject, hasProp, isObject } from './utils.js';
3
- const globalObject = getGlobalObject('history.ts', {});
2
+ import { assert, assertUsage, hasProp, isObject } from './utils.js';
4
3
  // Fill missing state information:
5
4
  // - `history.state` can uninitialized (i.e. `null`):
6
5
  // - The very first render
@@ -8,9 +7,10 @@ const globalObject = getGlobalObject('history.ts', {});
8
7
  // - The user clicks on an anchor link `<a href="#section">Section</a>` (Vike's `onLinkClick()` handler skips hash links).
9
8
  // - State information may be incomplete if `history.state` is set by an old Vike version. (E.g. `state.timestamp` was introduced for `pageContext.isBackwardNavigation` in `0.4.19`.)
10
9
  function initHistoryState() {
10
+ // No way found to add TypeScript types to `window.history.state`: https://github.com/microsoft/TypeScript/issues/36178
11
11
  let state = window.history.state;
12
12
  if (!state) {
13
- state = {};
13
+ state = { _isVikeEnhanced: true };
14
14
  }
15
15
  let hasModifications = false;
16
16
  if (!('timestamp' in state)) {
@@ -49,7 +49,7 @@ function saveScrollPosition() {
49
49
  function pushHistory(url, overwriteLastHistoryEntry) {
50
50
  if (!overwriteLastHistoryEntry) {
51
51
  const timestamp = getTimestamp();
52
- pushHistoryState({ timestamp, scrollPosition: null, triggeredBy: 'vike' }, url);
52
+ pushHistoryState({ timestamp, scrollPosition: null, triggeredBy: 'vike', _isVikeEnhanced: true }, url);
53
53
  }
54
54
  else {
55
55
  replaceHistoryState(getHistoryState(), url);
@@ -69,25 +69,29 @@ function assertState(state) {
69
69
  }
70
70
  }
71
71
  function replaceHistoryState(state, url) {
72
- window.history.replaceState(state, '', url ?? /* Passing `undefined` chokes older Edge versions */ null);
72
+ const url_ = url ?? null; // Passing `undefined` chokes older Edge versions.
73
+ window.history.replaceState(state, '', url_);
73
74
  }
74
75
  function pushHistoryState(state, url) {
75
- pushStateOriginal(state, '', url);
76
+ // Vike should call window.history.pushState() (and not the orignal `pushStateOriginal()`) so that other tools (e.g. user tracking) can listen to Vike's pushState() calls, see https://github.com/vikejs/vike/issues/1582.
77
+ window.history.pushState(state, '', url);
76
78
  }
77
79
  function monkeyPatchHistoryPushState() {
78
- globalObject.pushStateOriginal = globalObject.pushStateOriginal ?? window.history.pushState;
79
- window.history.pushState = (stateFromUser = {}, ...rest) => {
80
- assertUsage(null === stateFromUser || undefined === stateFromUser || isObject(stateFromUser), 'history.pushState(state) argument state must be an object');
81
- const state = {
82
- scrollPosition: getScrollPosition(),
83
- timestamp: getTimestamp(),
84
- ...stateFromUser,
85
- // Don't allow user to overwrite triggeredBy as it would break Vike's handling of the 'popstate' event
86
- triggeredBy: 'user'
87
- };
88
- return pushStateOriginal(state, ...rest);
80
+ const pushStateOriginal = window.history.pushState.bind(window.history);
81
+ window.history.pushState = (stateOriginal = {}, ...rest) => {
82
+ assertUsage(stateOriginal === undefined || stateOriginal === null || isObject(stateOriginal), 'history.pushState(state) argument state must be an object');
83
+ const stateEnhanced = isVikeEnhanced(stateOriginal)
84
+ ? stateOriginal
85
+ : {
86
+ _isVikeEnhanced: true,
87
+ scrollPosition: getScrollPosition(),
88
+ timestamp: getTimestamp(),
89
+ triggeredBy: 'user',
90
+ ...stateOriginal
91
+ };
92
+ return pushStateOriginal(stateEnhanced, ...rest);
89
93
  };
90
94
  }
91
- function pushStateOriginal(...args) {
92
- globalObject.pushStateOriginal.apply(history, args);
95
+ function isVikeEnhanced(state) {
96
+ return isObject(state) && '_isVikeEnhanced' in state;
93
97
  }
@@ -187,7 +187,7 @@ function analyzeImport(importStatement) {
187
187
  if (rawRE.test(moduleName)) {
188
188
  return { moduleName, skip: true };
189
189
  }
190
- /* We should not do this because of aliased imports
190
+ /* We shouldn't do this because of aliased imports
191
191
  if (!moduleName.startsWith('.')) {
192
192
  return { moduleName, skip: true }
193
193
  }
@@ -5,6 +5,7 @@ import glob from 'fast-glob';
5
5
  import { exec } from 'child_process';
6
6
  import { promisify } from 'util';
7
7
  import pc from '@brillout/picocolors';
8
+ import { isTemporaryBuildFile } from './transpileAndExecuteFile.js';
8
9
  const execA = promisify(exec);
9
10
  assertIsNotProductionRuntime();
10
11
  assertIsSingleModuleInstance('crawlPlusFiles.ts');
@@ -17,7 +18,13 @@ async function crawlPlusFiles(userRootDir, outDirAbsoluteFilesystem, isDev) {
17
18
  // config.outDir is outside of config.root => it's going to be ignored anyways
18
19
  outDirRelativeFromUserRootDir = null;
19
20
  }
20
- assert(outDirRelativeFromUserRootDir === null || !outDirRelativeFromUserRootDir.startsWith('.'));
21
+ assert(outDirRelativeFromUserRootDir === null ||
22
+ /* Not true if outDirRelativeFromUserRootDir starts with a hidden directory (i.e. a directory with a name that starts with `.`)
23
+ !outDirRelativeFromUserRootDir.startsWith('.') &&
24
+ */
25
+ (!outDirRelativeFromUserRootDir.startsWith('./') &&
26
+ //
27
+ !outDirRelativeFromUserRootDir.startsWith('../')));
21
28
  const timeBefore = new Date().getTime();
22
29
  let files = [];
23
30
  const res = await gitLsFiles(userRootDir, outDirRelativeFromUserRootDir);
@@ -29,6 +36,7 @@ async function crawlPlusFiles(userRootDir, outDirAbsoluteFilesystem, isDev) {
29
36
  else {
30
37
  files = await fastGlob(userRootDir, outDirRelativeFromUserRootDir);
31
38
  }
39
+ files = files.filter((file) => !isTemporaryBuildFile(file));
32
40
  {
33
41
  const timeAfter = new Date().getTime();
34
42
  const timeSpent = timeAfter - timeBefore;
@@ -2,7 +2,7 @@
2
2
  export { loadImportedFile };
3
3
  export { loadValueFile };
4
4
  export { loadConfigFile };
5
- import { assert, assertUsage, assertWarning, hasProp, assertIsNotProductionRuntime, isNpmPackageImport } from '../../../../utils.js';
5
+ import { assert, assertUsage, hasProp, assertIsNotProductionRuntime } from '../../../../utils.js';
6
6
  import { transpileAndExecuteFile } from './transpileAndExecuteFile.js';
7
7
  import { assertPlusFileExport } from '../../../../../../shared/page-configs/assertPlusFileExport.js';
8
8
  import pc from '@brillout/picocolors';
@@ -62,7 +62,6 @@ async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir
62
62
  const { importPath: importPathAbsolute } = importData;
63
63
  const filePathAbsoluteFilesystem = resolveImportPath(importData, configFilePath);
64
64
  assertImportPath(filePathAbsoluteFilesystem, importData, configFilePath);
65
- warnUserLandExtension(importPathAbsolute, configFilePath);
66
65
  const filePath = getFilePathResolved({ filePathAbsoluteFilesystem, userRootDir, importPathAbsolute });
67
66
  extendsConfigFiles.push(filePath);
68
67
  });
@@ -75,13 +74,6 @@ async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir
75
74
  const extendsFilePaths = extendsConfigFiles.map((f) => f.filePathAbsoluteFilesystem);
76
75
  return { extendsConfigs, extendsFilePaths };
77
76
  }
78
- function warnUserLandExtension(importPath, configFilePath) {
79
- // We preserve this feature because we may need it for eject
80
- assertWarning(isNpmPackageImport(importPath, {
81
- // Vike config files don't support path aliases. (If they do one day, then Vike will/should be able to resolve path aliases.)
82
- cannotBePathAlias: true
83
- }) || importPath.includes('/node_modules/'), `${configFilePath.filePathToShowToUser} uses ${pc.cyan('extends')} to inherit from ${pc.cyan(importPath)} which is a user-land file: this is experimental and may be remove at any time. Reach out to a maintainer if you need this.`, { onlyOnce: true });
84
- }
85
77
  function getExtendsImportData(configFileExports, configFilePath) {
86
78
  const { filePathToShowToUser } = configFilePath;
87
79
  const configFileExport = getConfigFileExport(configFileExports, filePathToShowToUser);
@@ -20,13 +20,22 @@ function resolveImport(configValue, importerFilePath, userRootDir, configEnv, co
20
20
  const fileExportPathToShowToUser = exportName === 'default' || exportName === configName ? [] : [exportName];
21
21
  let filePath;
22
22
  if (importPath.startsWith('.')) {
23
- // We need to resolve relative paths into absolute paths. Because the import paths are included in virtual files:
23
+ assert(importPath.startsWith('./') || importPath.startsWith('../'));
24
+ assertImportPath(filePathAbsoluteFilesystem, importData, importerFilePath);
25
+ filePath = getFilePathResolved({ filePathAbsoluteFilesystem, userRootDir });
26
+ // Imports are included in virtual files, thus the relative path of imports need to resolved.
24
27
  // ```
25
28
  // [vite] Internal server error: Failed to resolve import "./onPageTransitionHooks" from "virtual:vike:pageConfigValuesAll:client:/pages/index". Does the file exist?
26
29
  // ```
27
- assertImportPath(filePathAbsoluteFilesystem, importData, importerFilePath);
28
- const filePathAbsoluteUserRootDir = resolveImportPath_absoluteUserRootDir(filePathAbsoluteFilesystem, importData, importerFilePath, userRootDir);
29
- filePath = getFilePathResolved({ filePathAbsoluteUserRootDir, userRootDir });
30
+ assertUsage(filePath.filePathAbsoluteUserRootDir, `${importerFilePath.filePathToShowToUser} imports a relative path ${pc.cyan(importPath)} resolving outside of ${userRootDir} which is forbidden: import from a relative path inside ${userRootDir}, or import from a dependency's package.json#exports entry instead`);
31
+ // Alternativey, we can try one of the following but last time we tried none of the following worked.
32
+ // /*
33
+ // assert(filePathAbsoluteFilesystem.startsWith('/'))
34
+ // filePath = `/@fs${filePathAbsoluteFilesystem}`
35
+ // /*/
36
+ // assert(filePathAbsoluteUserRootDir.startsWith('../'))
37
+ // filePathAbsoluteUserRootDir = '/' + filePathAbsoluteUserRootDir
38
+ // //*/
30
39
  }
31
40
  else {
32
41
  // importPath can be:
@@ -51,28 +60,6 @@ function resolveImport(configValue, importerFilePath, userRootDir, configEnv, co
51
60
  fileExportPathToShowToUser
52
61
  };
53
62
  }
54
- function resolveImportPath_absoluteUserRootDir(filePathAbsoluteFilesystem, importData, configFilePath, userRootDir) {
55
- assertPosixPath(userRootDir);
56
- let filePathAbsoluteUserRootDir;
57
- if (filePathAbsoluteFilesystem.startsWith(userRootDir)) {
58
- filePathAbsoluteUserRootDir = getVitePathFromAbsolutePath(filePathAbsoluteFilesystem, userRootDir);
59
- }
60
- else {
61
- assertUsage(false, `${configFilePath.filePathToShowToUser} imports from a relative path ${pc.cyan(importData.importPath)} outside of ${userRootDir} which is forbidden: import from a relative path inside ${userRootDir}, or import from a dependency's package.json#exports entry instead`);
62
- // None of the following works. Seems to be a Vite bug?
63
- // /*
64
- // assert(filePathAbsoluteFilesystem.startsWith('/'))
65
- // filePath = `/@fs${filePathAbsoluteFilesystem}`
66
- // /*/
67
- // filePathAbsoluteUserRootDir = path.posix.relative(userRootDir, filePathAbsoluteFilesystem)
68
- // assert(filePathAbsoluteUserRootDir.startsWith('../'))
69
- // filePathAbsoluteUserRootDir = '/' + filePathAbsoluteUserRootDir
70
- // //*/
71
- }
72
- assertPosixPath(filePathAbsoluteUserRootDir);
73
- assert(filePathAbsoluteUserRootDir.startsWith('/'));
74
- return filePathAbsoluteUserRootDir;
75
- }
76
63
  function resolveImportPath(importData, importerFilePath) {
77
64
  const importerFilePathAbsolute = importerFilePath.filePathAbsoluteFilesystem;
78
65
  assertPosixPath(importerFilePathAbsolute);
@@ -93,6 +80,7 @@ function assertImportPath(filePathAbsoluteFilesystem, importData, importerFilePa
93
80
  : `The import ${pc.cyan(importString)} defined in ${filePathToShowToUser}`;
94
81
  const errIntro2 = `${errIntro} couldn't be resolved: does ${importPathString}`;
95
82
  if (importPath.startsWith('.')) {
83
+ assert(importPath.startsWith('./') || importPath.startsWith('../'));
96
84
  assertUsage(false, `${errIntro2} point to an existing file?`);
97
85
  }
98
86
  else {
@@ -119,12 +107,3 @@ function assertFileEnv(filePathForEnvCheck, configEnv, configName) {
119
107
  function clearFilesEnvMap() {
120
108
  filesEnvMap.clear();
121
109
  }
122
- function getVitePathFromAbsolutePath(filePathAbsoluteFilesystem, root) {
123
- assertPosixPath(filePathAbsoluteFilesystem);
124
- assertPosixPath(root);
125
- assert(filePathAbsoluteFilesystem.startsWith(root));
126
- let vitePath = path.posix.relative(root, filePathAbsoluteFilesystem);
127
- assert(!vitePath.startsWith('/') && !vitePath.startsWith('.'));
128
- vitePath = '/' + vitePath;
129
- return vitePath;
130
- }
@@ -2,7 +2,7 @@ export { transformFileImports };
2
2
  export { parseImportData };
3
3
  export { isImportData };
4
4
  export type { ImportData };
5
- declare function transformFileImports(code: string, filePathToShowToUser2: string, pointerImports: 'all' | Record<string, boolean>, skipWarnings?: true): string | null;
5
+ declare function transformFileImports(code: string, filePathToShowToUser2: string, pointerImports: Record<string, boolean> | 'all', skipWarnings?: true): string | null;
6
6
  /**
7
7
  * Data Structure holding info about import statement:
8
8
  * `import { someExport as someImport } from './some-file'`
@@ -1,7 +1,7 @@
1
1
  export { transpileAndExecuteFile };
2
2
  export { getConfigBuildErrorFormatted };
3
3
  export { getConfigExecutionErrorIntroMsg };
4
- export { isTmpFile };
4
+ export { isTemporaryBuildFile };
5
5
  import 'source-map-support/register.js';
6
6
  import type { FilePathResolved } from '../../../../../../shared/page-configs/FilePath.js';
7
7
  declare function transpileAndExecuteFile(filePath: FilePathResolved, userRootDir: string, isConfigFile: boolean | 'is-extension-config'): Promise<{
@@ -9,4 +9,4 @@ declare function transpileAndExecuteFile(filePath: FilePathResolved, userRootDir
9
9
  }>;
10
10
  declare function getConfigBuildErrorFormatted(err: unknown): null | string;
11
11
  declare function getConfigExecutionErrorIntroMsg(err: unknown): string | null;
12
- declare function isTmpFile(filePath: string): boolean;
12
+ declare function isTemporaryBuildFile(filePath: string): boolean;
@@ -1,13 +1,13 @@
1
1
  export { transpileAndExecuteFile };
2
2
  export { getConfigBuildErrorFormatted };
3
3
  export { getConfigExecutionErrorIntroMsg };
4
- export { isTmpFile };
4
+ export { isTemporaryBuildFile };
5
5
  import { build, formatMessages } from 'esbuild';
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
8
  import pc from '@brillout/picocolors';
9
9
  import { import_ } from '@brillout/import';
10
- import { assertPosixPath, getRandomId, assertIsNotProductionRuntime, assert, assertWarning, isObject, toPosixPath, assertUsage, isJavaScriptFile, createDebugger } from '../../../../utils.js';
10
+ import { assertPosixPath, getRandomId, assertIsNotProductionRuntime, assert, assertWarning, isObject, toPosixPath, assertUsage, isJavaScriptFile, createDebugger, assertPathIsFilesystemAbsolute } from '../../../../utils.js';
11
11
  import { transformFileImports } from './transformFileImports.js';
12
12
  import { vikeConfigDependencies } from '../getVikeConfig.js';
13
13
  import 'source-map-support/register.js';
@@ -79,87 +79,96 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
79
79
  // Esbuild still sometimes removes unused imports because of TypeScript: https://github.com/evanw/esbuild/issues/3034
80
80
  treeShaking: false,
81
81
  minify: false,
82
- metafile: transformImports !== 'all',
83
- bundle: transformImports !== 'all'
82
+ metafile: true,
83
+ bundle: true
84
84
  };
85
- let pointerImports;
86
- if (transformImports === 'all') {
87
- pointerImports = 'all';
88
- options.packages = 'external';
89
- }
90
- else {
91
- const pointerImports_ = (pointerImports = {});
92
- options.plugins = [
93
- // Determine what import should be externalized (and then transformed to a pointer/fake import)
94
- {
95
- name: 'vike:externalize-heuristic',
96
- setup(build) {
97
- // https://github.com/evanw/esbuild/issues/3095#issuecomment-1546916366
85
+ let pointerImports = {};
86
+ options.plugins = [
87
+ // Determine whether an import should be:
88
+ // - A pointer import
89
+ // - Externalized
90
+ {
91
+ name: 'vike-esbuild',
92
+ setup(build) {
93
+ // https://github.com/brillout/esbuild-playground
94
+ build.onResolve({ filter: /.*/ }, async (args) => {
95
+ if (args.kind !== 'import-statement')
96
+ return;
97
+ // Avoid infinite loop: https://github.com/evanw/esbuild/issues/3095#issuecomment-1546916366
98
98
  const useEsbuildResolver = 'useEsbuildResolver';
99
- // https://github.com/brillout/esbuild-playground
100
- build.onResolve({ filter: /.*/ }, async (args) => {
101
- if (args.kind !== 'import-statement')
102
- return;
103
- if (args.pluginData?.[useEsbuildResolver])
104
- return;
105
- const { path, ...opts } = args;
106
- opts.pluginData = { [useEsbuildResolver]: true };
107
- const resolved = await build.resolve(path, opts);
108
- resolved.path = toPosixPath(resolved.path);
109
- // vike-{react,vue,solid} follow the convention that their config export resolves to a file named +config.js
110
- // - This is temporary, see comment below.
111
- const isVikeExtensionConfigImport = resolved.path.endsWith('+config.js');
112
- const isPointerImport =
99
+ if (args.pluginData?.[useEsbuildResolver])
100
+ return;
101
+ const { path, ...opts } = args;
102
+ opts.pluginData = { [useEsbuildResolver]: true };
103
+ const resolved = await build.resolve(path, opts);
104
+ if (resolved.errors.length > 0) {
105
+ /* We could do the following to let Node.js throw the error, but we don't because the error shown by esbuild is prettier: the Node.js error refers to the transpiled [build-f7i251e0iwnw]+config.ts.mjs file which isn't that nice, whereas esbuild refers to the source +config.ts file.
106
+ pointerImports[args.path] = false
107
+ return { external: true }
108
+ */
109
+ // Let esbuild throw the error. (It throws a nice & pretty error.)
110
+ cleanEsbuildErrors(resolved.errors);
111
+ return resolved;
112
+ }
113
+ assert(resolved.path);
114
+ resolved.path = toPosixPath(resolved.path);
115
+ // vike-{react,vue,solid} follow the convention that their config export resolves to a file named +config.js
116
+ // - This is temporary, see comment below.
117
+ const isVikeExtensionConfigImport = resolved.path.endsWith('+config.js');
118
+ const isPointerImport = transformImports === 'all' ||
113
119
  // .jsx, .vue, .svg, ... => obviously not config code
114
120
  !isJavaScriptFile(resolved.path) ||
115
- // Import of a Vike extension config => make it a pointer import because we want to show nice error messages (that can display whether a configas been set by the user or by a Vike extension).
116
- // - We should have Node.js directly load vike-{react,vue,solid} while enforcing Vike extensions to set 'name' in their +config.js file.
117
- // - vike@0.4.162 already started soft-requiring Vike extensions to set the name config
118
- isVikeExtensionConfigImport ||
119
- // Cannot be resolved by esbuild => take a leap of faith and make it a pointer import.
120
- // - For example if esbuild cannot resolve a path alias while Vite can.
121
- // - When tsconfig.js#compilerOptions.paths is set, then esbuild is able to resolve the path alias.
122
- resolved.errors.length > 0;
123
- pointerImports_[resolved.path] = isPointerImport;
124
- assertPosixPath(resolved.path);
125
- const isExternal = isPointerImport ||
126
- // npm package imports that aren't pointer imports (e.g. importing a Vite plugin)
127
- resolved.path.includes('/node_modules/');
128
- if (debug.isActivated)
129
- debug('onResolved()', { args, resolved, isPointerImport, isExternal });
130
- if (isExternal) {
131
- return { external: true, path: resolved.path };
132
- }
133
- else {
134
- return resolved;
135
- }
136
- });
137
- }
138
- },
139
- // Track dependencies
140
- {
141
- name: 'vike:dependency-tracker',
142
- setup(b) {
143
- b.onLoad({ filter: /./ }, (args) => {
144
- // We collect the dependency `args.path` in case the bulid fails (upon build error => error is thrown => no metafile)
145
- let { path } = args;
146
- path = toPosixPath(path);
147
- vikeConfigDependencies.add(path);
148
- return undefined;
149
- });
150
- /* To exhaustively collect all dependencies upon build failure, we would also need to use onResolve().
151
- * - Because onLoad() isn't call if the config dependency can't be resolved.
152
- * - For example, the following breaks auto-reload (the config is stuck in its error state and the user needs to touch the importer for the config to reload):
153
- * ```bash
154
- * mv ./some-config-dependency.js /tmp/ && mv /tmp/some-config-dependency.js .
155
- * ```
156
- * - But implementing a fix is complex and isn't worth it.
157
- b.onResolve(...)
158
- */
159
- }
121
+ // Import of a Vike extension config => make it a pointer import because we want to show nice error messages (that can display whether a configas been set by the user or by a Vike extension).
122
+ // - We should have Node.js directly load vike-{react,vue,solid} while enforcing Vike extensions to set 'name' in their +config.js file.
123
+ // - vike@0.4.162 already started soft-requiring Vike extensions to set the name config
124
+ isVikeExtensionConfigImport ||
125
+ // Cannot be resolved by esbuild => take a leap of faith and make it a pointer import.
126
+ // - For example if esbuild cannot resolve a path alias while Vite can.
127
+ // - When tsconfig.js#compilerOptions.paths is set, then esbuild is able to resolve the path alias.
128
+ resolved.errors.length > 0;
129
+ pointerImports[resolved.path] = isPointerImport;
130
+ assertPosixPath(resolved.path);
131
+ const isExternal = isPointerImport ||
132
+ // Performance: npm package imports that aren't pointer imports can be externalized. For example, if Vike eventually adds support for setting Vite configs in the vike.config.js file, then the user may import a Vite plugin in his vike.config.js file. (We could as well let esbuild always transpile /node_modules/ code but it would be useless and would unnecessarily slow down transpilation.)
133
+ resolved.path.includes('/node_modules/');
134
+ if (debug.isActivated)
135
+ debug('onResolved()', { args, resolved, isPointerImport, isExternal });
136
+ // We need esbuild to resolve path aliases so that we can use:
137
+ // isNpmPackageImport(str, { cannotBePathAlias: true })
138
+ // assertIsNpmPackageImport()
139
+ assertPathIsFilesystemAbsolute(resolved.path);
140
+ if (isExternal) {
141
+ return { external: true, path: resolved.path };
142
+ }
143
+ else {
144
+ return resolved;
145
+ }
146
+ });
160
147
  }
161
- ];
162
- }
148
+ },
149
+ // Track dependencies
150
+ {
151
+ name: 'vike:dependency-tracker',
152
+ setup(b) {
153
+ b.onLoad({ filter: /./ }, (args) => {
154
+ // We collect the dependency `args.path` in case the bulid fails (upon build error => error is thrown => no metafile)
155
+ let { path } = args;
156
+ path = toPosixPath(path);
157
+ vikeConfigDependencies.add(path);
158
+ return undefined;
159
+ });
160
+ /* To exhaustively collect all dependencies upon build failure, we would also need to use onResolve().
161
+ * - Because onLoad() isn't call if the config dependency can't be resolved.
162
+ * - For example, the following breaks auto-reload (the config is stuck in its error state and the user needs to touch the importer for the config to reload):
163
+ * ```bash
164
+ * mv ./some-config-dependency.js /tmp/ && mv /tmp/some-config-dependency.js .
165
+ * ```
166
+ * - But implementing a fix is complex and isn't worth it.
167
+ b.onResolve(...)
168
+ */
169
+ }
170
+ }
171
+ ];
163
172
  let result;
164
173
  try {
165
174
  result = await build(options);
@@ -169,15 +178,13 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
169
178
  throw err;
170
179
  }
171
180
  // Track dependencies
172
- if (transformImports !== 'all') {
173
- assert(result.metafile);
174
- Object.keys(result.metafile.inputs).forEach((filePathRelative) => {
175
- filePathRelative = toPosixPath(filePathRelative);
176
- assertPosixPath(userRootDir);
177
- const filePathAbsoluteFilesystem = path.posix.join(userRootDir, filePathRelative);
178
- vikeConfigDependencies.add(filePathAbsoluteFilesystem);
179
- });
180
- }
181
+ assert(result.metafile);
182
+ Object.keys(result.metafile.inputs).forEach((filePathRelative) => {
183
+ filePathRelative = toPosixPath(filePathRelative);
184
+ assertPosixPath(userRootDir);
185
+ const filePathAbsoluteFilesystem = path.posix.join(userRootDir, filePathRelative);
186
+ vikeConfigDependencies.add(filePathAbsoluteFilesystem);
187
+ });
181
188
  const code = result.outputFiles[0].text;
182
189
  assert(typeof code === 'string');
183
190
  return { code, pointerImports };
@@ -186,7 +193,7 @@ async function executeTranspiledFile(filePath, code) {
186
193
  const { filePathAbsoluteFilesystem } = filePath;
187
194
  // Alternative to using a temporary file: https://github.com/vitejs/vite/pull/13269
188
195
  // - But seems to break source maps, so I don't think it's worth it
189
- const filePathTmp = getFilePathTmp(filePathAbsoluteFilesystem);
196
+ const filePathTmp = getTemporaryBuildFilePath(filePathAbsoluteFilesystem);
190
197
  fs.writeFileSync(filePathTmp, code);
191
198
  const clean = () => fs.unlinkSync(filePathTmp);
192
199
  let fileExports = {};
@@ -243,20 +250,19 @@ function getConfigExecutionErrorIntroMsg(err) {
243
250
  const errIntroMsg = execErrIntroMsg.get(err);
244
251
  return errIntroMsg ?? null;
245
252
  }
246
- const tmpPrefix = `[build-`;
247
- function getFilePathTmp(filePathAbsoluteFilesystem) {
253
+ function getTemporaryBuildFilePath(filePathAbsoluteFilesystem) {
248
254
  assertPosixPath(filePathAbsoluteFilesystem);
249
255
  const dirname = path.posix.dirname(filePathAbsoluteFilesystem);
250
256
  const filename = path.posix.basename(filePathAbsoluteFilesystem);
251
- // Syntax with semicolon `[build:${/*...*/}]` doesn't work on Windows: https://github.com/vikejs/vike/issues/800#issuecomment-1517329455
252
- const tag = `${tmpPrefix}${getRandomId(12)}]`;
253
- const filePathTmp = path.posix.join(dirname, `${tag}${filename}.mjs`);
257
+ // Syntax with semicolon `build:${/*...*/}` doesn't work on Windows: https://github.com/vikejs/vike/issues/800#issuecomment-1517329455
258
+ const filePathTmp = path.posix.join(dirname, `${filename}.build-${getRandomId(12)}.mjs`);
259
+ assert(isTemporaryBuildFile(filePathTmp));
254
260
  return filePathTmp;
255
261
  }
256
- function isTmpFile(filePath) {
262
+ function isTemporaryBuildFile(filePath) {
257
263
  assertPosixPath(filePath);
258
264
  const fileName = path.posix.basename(filePath);
259
- return fileName.startsWith(tmpPrefix);
265
+ return /\.build-[a-z0-9]{12}\.mjs$/.test(fileName);
260
266
  }
261
267
  function isHeaderFile(filePath) {
262
268
  assertPosixPath(filePath);
@@ -300,3 +306,23 @@ function getErrIntroMsg(operation, filePath) {
300
306
  ].join(' ');
301
307
  return msg;
302
308
  }
309
+ function cleanEsbuildErrors(errors) {
310
+ errors.forEach((e) => (e.notes = e.notes.filter((note) =>
311
+ // Remove note:
312
+ // ```shell
313
+ // You can mark the path "#root/renderer/onRenderHtml_typo" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
314
+ // ```
315
+ //
316
+ // From error:
317
+ // ```shell
318
+ // ✘ [ERROR] Could not resolve "#root/renderer/onRenderHtml_typo" [plugin vike-esbuild]
319
+ //
320
+ // renderer/+config.h.js:1:29:
321
+ // 1 │ import { onRenderHtml } from "#root/renderer/onRenderHtml_typo"
322
+ // ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
323
+ //
324
+ // You can mark the path "#root/renderer/onRenderHtml_typo" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
325
+ //
326
+ // ```
327
+ !note.text.includes('as external to exclude it from the bundle'))));
328
+ }
@@ -7,7 +7,7 @@ import { assertPosixPath, assert, isObject, assertUsage, assertWarning, objectEn
7
7
  import path from 'path';
8
8
  import { configDefinitionsBuiltIn, configDefinitionsBuiltInGlobal } from './getVikeConfig/configDefinitionsBuiltIn.js';
9
9
  import { getLocationId, getFilesystemRouteString, getFilesystemRouteDefinedBy, isInherited, sortAfterInheritanceOrder, isGlobalLocation, applyFilesystemRoutingRootEffect } from './getVikeConfig/filesystemRouting.js';
10
- import { isTmpFile } from './getVikeConfig/transpileAndExecuteFile.js';
10
+ import { isTemporaryBuildFile } from './getVikeConfig/transpileAndExecuteFile.js';
11
11
  import { isConfigInvalid, isConfigInvalid_set } from '../../../../runtime/renderPage/isConfigInvalid.js';
12
12
  import { getViteDevServer } from '../../../../runtime/globalContext.js';
13
13
  import { logConfigError, logConfigErrorRecover } from '../../../shared/loggerNotProd.js';
@@ -745,7 +745,7 @@ async function findPlusFiles(userRootDir, outDirRoot, isDev) {
745
745
  }
746
746
  function getConfigName(filePath) {
747
747
  assertPosixPath(filePath);
748
- if (isTmpFile(filePath))
748
+ if (isTemporaryBuildFile(filePath))
749
749
  return null;
750
750
  const fileName = path.posix.basename(filePath);
751
751
  // assertNoUnexpectedPlusSign(filePath, fileName)
@@ -776,7 +776,30 @@ function assertNoUnexpectedPlusSign(filePath: string, fileName: string) {
776
776
  }
777
777
  */
778
778
  function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
779
- let errMsg = `${filePathToShowToUser} defines an unknown config ${pc.cyan(configName)}`;
779
+ {
780
+ const ui = ['vike-react', 'vike-vue', 'vike-solid'];
781
+ const knownVikeExntensionConfigs = {
782
+ description: ui,
783
+ favicon: ui,
784
+ Head: ui,
785
+ Layout: ui,
786
+ onCreateApp: ['vike-vue'],
787
+ title: ui,
788
+ ssr: ui,
789
+ stream: ui,
790
+ Wrapper: ui
791
+ };
792
+ if (configName in knownVikeExntensionConfigs) {
793
+ const requiredVikeExtension = knownVikeExntensionConfigs[configName];
794
+ assertUsage(false, [
795
+ `${filePathToShowToUser} uses the config ${pc.cyan(configName)} (https://vike.dev/${configName})`,
796
+ `which requires the Vike extension ${requiredVikeExtension.map((e) => pc.bold(e)).join('/')}.`,
797
+ `Make sure to install the Vike extension,`,
798
+ `and make sure it applies to ${filePathToShowToUser} as explained at https://vike.dev/extends#inheritance.`
799
+ ].join(' '));
800
+ }
801
+ }
802
+ let errMsg = `${filePathToShowToUser} sets an unknown config ${pc.cyan(configName)}`;
780
803
  let configNameSimilar = null;
781
804
  if (configName === 'page') {
782
805
  configNameSimilar = 'Page';
@@ -784,17 +807,13 @@ function handleUnknownConfig(configName, configNames, filePathToShowToUser) {
784
807
  else {
785
808
  configNameSimilar = getMostSimilar(configName, configNames);
786
809
  }
787
- if (configNameSimilar || configName === 'page') {
788
- assert(configNameSimilar);
810
+ if (configNameSimilar) {
789
811
  assert(configNameSimilar !== configName);
790
- errMsg += `, did you mean to define ${pc.cyan(configNameSimilar)} instead?`;
812
+ errMsg += `, did you mean to set ${pc.cyan(configNameSimilar)} instead?`;
791
813
  if (configName === 'page') {
792
814
  errMsg += ` (The name of the config ${pc.cyan('Page')} starts with a capital letter ${pc.cyan('P')} because it usually defines a UI component: a ubiquitous JavaScript convention is to start the name of UI components with a capital letter.)`;
793
815
  }
794
816
  }
795
- else {
796
- errMsg += `, you need to define the config ${pc.cyan(configName)} by using ${pc.cyan('config.meta')} https://vike.dev/meta`;
797
- }
798
817
  assertUsage(false, errMsg);
799
818
  }
800
819
  function determineRouteFilesystem(locationId, configValueSources) {
@@ -87,7 +87,12 @@ function getFilePathAbsoluteUserRootDir({ filePathAbsoluteFilesystem, userRootDi
87
87
  assert(filePathRelative.startsWith('../'));
88
88
  return null;
89
89
  }
90
- assert(!filePathRelative.startsWith('.') && !filePathRelative.startsWith('/'));
90
+ assert(!filePathRelative.startsWith('/') &&
91
+ /* Not true if filePathRelative starts with a hidden directory (i.e. a directory with a name that starts with `.`)
92
+ !filePathRelative.startsWith('.') &&
93
+ */
94
+ !filePathRelative.startsWith('./') &&
95
+ !filePathRelative.startsWith('../'));
91
96
  const filePathAbsoluteUserRootDir = `/${filePathRelative}`;
92
97
  assert(filePathAbsoluteUserRootDir === getFilePathAbsoluteUserRootDir2(filePathAbsoluteFilesystem, userRootDir));
93
98
  return filePathAbsoluteUserRootDir;
@@ -13,7 +13,7 @@ function analyzePage(pageFilesAll, pageConfig, pageId) {
13
13
  const clientDependencies = [];
14
14
  clientDependencies.push({
15
15
  id: getVirtualFileIdPageConfigValuesAll(pageConfig.pageId, true),
16
- onlyAssets: false,
16
+ onlyAssets: isClientSideRenderable ? false : true,
17
17
  eagerlyImported: false
18
18
  });
19
19
  // In production we inject the import of the server virtual module with ?extractAssets inside the client virtual module