vike 0.4.159-commit-71760c7 → 0.4.159-commit-0424983

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.
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
9
9
  const configDefinitionsBuiltIn_js_1 = require("./getVikeConfig/configDefinitionsBuiltIn.js");
10
10
  const filesystemRouting_js_1 = require("./getVikeConfig/filesystemRouting.js");
11
11
  const transpileAndExecuteFile_js_1 = require("./transpileAndExecuteFile.js");
12
- const transformImportStatements_js_1 = require("./transformImportStatements.js");
12
+ const transformImports_js_1 = require("./transformImports.js");
13
13
  const isConfigInvalid_js_1 = require("../../../../runtime/renderPage/isConfigInvalid.js");
14
14
  const globalContext_js_1 = require("../../../../runtime/globalContext.js");
15
15
  const loggerNotProd_js_1 = require("../../../shared/loggerNotProd.js");
@@ -90,7 +90,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
90
90
  let interfaceFilesByLocationId = {};
91
91
  // Config files
92
92
  await Promise.all(configFiles.map(async (filePath) => {
93
- const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, []);
93
+ const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, [], false);
94
94
  const interfaceFile = getInterfaceFileFromConfigFile(configFile, false);
95
95
  const locationId = (0, filesystemRouting_js_1.getLocationId)(filePath.filePathAbsoluteVite);
96
96
  interfaceFilesByLocationId[locationId] = interfaceFilesByLocationId[locationId] ?? [];
@@ -582,7 +582,7 @@ function isDefiningPageConfig(configName) {
582
582
  function resolveImport(configValue, importerFilePath, userRootDir, configEnv, configName) {
583
583
  if (typeof configValue !== 'string')
584
584
  return null;
585
- const importData = (0, transformImportStatements_js_1.parseImportData)(configValue);
585
+ const importData = (0, transformImports_js_1.parseImportData)(configValue);
586
586
  if (!importData)
587
587
  return null;
588
588
  const { importPath, exportName } = importData;
@@ -845,10 +845,10 @@ function getConfigName(filePath) {
845
845
  return configName;
846
846
  }
847
847
  }
848
- async function loadConfigFile(configFilePath, userRootDir, visited) {
848
+ async function loadConfigFile(configFilePath, userRootDir, visited, isConfigOfExtension) {
849
849
  const { filePathAbsoluteFilesystem } = configFilePath;
850
850
  assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem);
851
- const { fileExports } = await (0, transpileAndExecuteFile_js_1.transpileAndExecuteFile)(configFilePath, false, userRootDir);
851
+ const { fileExports } = await (0, transpileAndExecuteFile_js_1.transpileAndExecuteFile)(configFilePath, false, userRootDir, isConfigOfExtension);
852
852
  const { extendsConfigs, extendsFilePaths } = await loadExtendsConfigs(fileExports, configFilePath, userRootDir, [
853
853
  ...visited,
854
854
  filePathAbsoluteFilesystem
@@ -890,7 +890,7 @@ async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir
890
890
  });
891
891
  const extendsConfigs = [];
892
892
  await Promise.all(extendsConfigFiles.map(async (configFilePath) => {
893
- const result = await loadConfigFile(configFilePath, userRootDir, visited);
893
+ const result = await loadConfigFile(configFilePath, userRootDir, visited, true);
894
894
  extendsConfigs.push(result.configFile);
895
895
  extendsConfigs.push(...result.extendsConfigs);
896
896
  }));
@@ -941,7 +941,7 @@ function getExtendsImportData(configFileExports, configFilePath) {
941
941
  (0, utils_js_1.assertUsage)(false, wrongUsage);
942
942
  }
943
943
  const extendsImportData = extendList.map((importDataSerialized) => {
944
- const importData = (0, transformImportStatements_js_1.parseImportData)(importDataSerialized);
944
+ const importData = (0, transformImports_js_1.parseImportData)(importDataSerialized);
945
945
  (0, utils_js_1.assertUsage)(importData, wrongUsage);
946
946
  return importData;
947
947
  });
@@ -3,14 +3,16 @@ 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.isVikeRealImport = exports.isImportData = exports.parseImportData = exports.transformImportStatements = void 0;
6
+ exports.isImportData = exports.parseImportData = exports.transformImports = void 0;
7
7
  // Playground: https://github.com/brillout/acorn-playground
8
8
  // Import attributes support: https://github.com/acornjs/acorn/issues/983
9
9
  // - Isn't stage 4 yet: https://github.com/tc39/proposal-import-attributes
10
10
  const acorn_1 = require("acorn");
11
11
  const utils_js_1 = require("../../../utils.js");
12
12
  const picocolors_1 = __importDefault(require("@brillout/picocolors"));
13
- function transformImportStatements(code, filePathToShowToUser2) {
13
+ function transformImports(code, filePathToShowToUser2,
14
+ // For ./transformImports.spec.ts
15
+ skipWarnings) {
14
16
  const spliceOperations = [];
15
17
  const fileImportsTransformed = [];
16
18
  // Performance trick
@@ -24,9 +26,29 @@ function transformImportStatements(code, filePathToShowToUser2) {
24
26
  return;
25
27
  const importPath = node.source.value;
26
28
  (0, utils_js_1.assert)(typeof importPath === 'string');
27
- const { start, end } = node;
28
- if (isVikeRealImport(code, end))
29
+ // - This doesn't work, to make it work we would need to run esbuild twice: esbuild for TypeScript to JavaScript => transformImports() => esbuild for bundling.
30
+ // - Or we use an esbuild plugin to apply transformImports(). Maybe we can completely skip the need for acorn?
31
+ // - ?real breaks TypeScript, and TypeScript isn't working on supporting query params: https://github.com/microsoft/TypeScript/issues/10988#issuecomment-867135453
32
+ // - Import attributes would be the best.
33
+ // - But it only works with Node.js >=21: https://nodejs.org/api/esm.html#import-attributes
34
+ // - But it's probably ok to tell users "to use real imports you need Node.js 21 or above".
35
+ // - It seems to work well with the latest TypeScript versions: TypeScript doesn't complain upon `with { type: 'unknown-to-typescript' }` and go-to-definition & types are preserved.
36
+ // - Esbuid seems to support it: https://esbuild.github.io/plugins/#on-load-arguments:~:text=This%20contains%20a%20map%20of%20the%20import%20attributes%20that
37
+ // - acorn supports it over an acorn plugin: https://github.com/acornjs/acorn/issues/983
38
+ // - Maybe we can use an esbuild plugin instead of acorn to apply transformImports()?
39
+ // - Using a magic comment `// @vike-real-import` is tricky:
40
+ // - Esbuild removes comments: https://github.com/evanw/esbuild/issues/1439#issuecomment-877656182
41
+ // - Using source maps to track these magic comments is brittle (source maps can easily break)
42
+ if (importPath.endsWith('?real')) {
43
+ const { start, end } = node.source;
44
+ spliceOperations.push({
45
+ start,
46
+ end,
47
+ replacement: importPath.slice(0, -1 * '?real'.length)
48
+ });
29
49
  return;
50
+ }
51
+ const { start, end } = node;
30
52
  const importStatementCode = code.slice(start, end);
31
53
  // No variable imported
32
54
  if (node.specifiers.length === 0) {
@@ -42,10 +64,12 @@ function transformImportStatements(code, filePathToShowToUser2) {
42
64
  `As explained in https://vike.dev/header-file the following import in ${filePathToShowToUser2} has no effect:`,
43
65
  quote
44
66
  ].join('\n');
45
- if (!isWarning) {
46
- (0, utils_js_1.assertUsage)(false, errMsg);
67
+ if (!skipWarnings) {
68
+ if (!isWarning) {
69
+ (0, utils_js_1.assertUsage)(false, errMsg);
70
+ }
71
+ (0, utils_js_1.assertWarning)(false, errMsg, { onlyOnce: true });
47
72
  }
48
- (0, utils_js_1.assertWarning)(false, errMsg, { onlyOnce: true });
49
73
  }
50
74
  let replacement = '';
51
75
  node.specifiers.forEach((specifier) => {
@@ -82,7 +106,7 @@ function transformImportStatements(code, filePathToShowToUser2) {
82
106
  const codeMod = spliceMany(code, spliceOperations);
83
107
  return { code: codeMod, fileImportsTransformed, noTransformation: false };
84
108
  }
85
- exports.transformImportStatements = transformImportStatements;
109
+ exports.transformImports = transformImports;
86
110
  function getImports(code) {
87
111
  const { body } = (0, acorn_1.parse)(code, {
88
112
  ecmaVersion: 'latest',
@@ -150,7 +174,7 @@ function spliceMany(str, operations) {
150
174
  .join('');
151
175
  endPrev = end;
152
176
  });
153
- strMod += str.slice(endPrev, str.length - 1);
177
+ strMod += str.slice(endPrev, str.length);
154
178
  return strMod;
155
179
  }
156
180
  function indent(str) {
@@ -159,11 +183,3 @@ function indent(str) {
159
183
  .map((s) => ` ${s}`)
160
184
  .join('\n');
161
185
  }
162
- function isVikeRealImport(code, posStart) {
163
- let posEnd = code.indexOf('\n', posStart);
164
- if (posEnd === -1)
165
- posEnd = code.length;
166
- const lineEnd = code.slice(posStart, posEnd);
167
- return lineEnd.includes('@vike-real-import');
168
- }
169
- exports.isVikeRealImport = isVikeRealImport;
@@ -10,50 +10,57 @@ const path_1 = __importDefault(require("path"));
10
10
  const picocolors_1 = __importDefault(require("@brillout/picocolors"));
11
11
  const import_1 = require("@brillout/import");
12
12
  const utils_js_1 = require("../../../utils.js");
13
- const transformImportStatements_js_1 = require("./transformImportStatements.js");
13
+ const transformImports_js_1 = require("./transformImports.js");
14
14
  const getVikeConfig_js_1 = require("./getVikeConfig.js");
15
15
  require("source-map-support/register.js");
16
16
  const getConfigFileExport_js_1 = require("./getConfigFileExport.js");
17
17
  (0, utils_js_1.assertIsNotProductionRuntime)();
18
- async function transpileAndExecuteFile(filePath, isValueFile, userRootDir) {
19
- const { code, fileImportsTransformed } = await transpileFile(filePath, isValueFile, userRootDir);
18
+ async function transpileAndExecuteFile(filePath, isValueFile, userRootDir, isConfigOfExtension = false) {
19
+ const { code, fileImportsTransformed } = await transpileFile(filePath, isValueFile, userRootDir, isConfigOfExtension);
20
20
  const { fileExports } = await executeFile(filePath, code, fileImportsTransformed, isValueFile);
21
21
  return { fileExports };
22
22
  }
23
23
  exports.transpileAndExecuteFile = transpileAndExecuteFile;
24
- async function transpileFile(filePath, isValueFile, userRootDir) {
24
+ async function transpileFile(filePath, isValueFile, userRootDir, isConfigOfExtension) {
25
25
  const { filePathAbsoluteFilesystem } = filePath;
26
+ const filePathToShowToUser2 = getFilePathToShowToUser2(filePath);
26
27
  (0, utils_js_1.assertPosixPath)(filePathAbsoluteFilesystem);
27
28
  getVikeConfig_js_1.vikeConfigDependencies.add(filePathAbsoluteFilesystem);
28
- let code = await transpileWithEsbuild(filePath, isValueFile, userRootDir);
29
+ const importsAreTransformed = !isConfigOfExtension && !isValueFile;
30
+ let code = await transpileWithEsbuild(filePath, userRootDir, importsAreTransformed, isValueFile);
29
31
  let fileImportsTransformed = null;
30
- {
31
- const res = transformImports(code, filePath, isValueFile);
32
+ if (importsAreTransformed) {
33
+ const res = transformImports_(code, filePath);
32
34
  if (res) {
33
35
  code = res.code;
34
36
  fileImportsTransformed = res.fileImportsTransformed;
35
37
  }
36
38
  }
39
+ else {
40
+ if (isHeaderFile(filePathAbsoluteFilesystem)) {
41
+ if (isValueFile) {
42
+ (0, utils_js_1.assertWarning)(false, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files only apply to +config.h.js, see https://vike.dev/header-file`, { onlyOnce: true });
43
+ }
44
+ else if (isConfigOfExtension) {
45
+ (0, utils_js_1.assertWarning)(false, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files don't apply to the config files of extensions`, { onlyOnce: true });
46
+ }
47
+ else {
48
+ (0, utils_js_1.assert)(false);
49
+ }
50
+ }
51
+ }
37
52
  return { code, fileImportsTransformed };
38
53
  }
39
- function transformImports(codeOriginal, filePath, isValueFile) {
40
- // Do we need to remove the imports?
54
+ function transformImports_(codeOriginal, filePath) {
41
55
  const { filePathAbsoluteFilesystem } = filePath;
42
56
  const filePathToShowToUser2 = getFilePathToShowToUser2(filePath);
43
- (0, utils_js_1.assertPosixPath)(filePathAbsoluteFilesystem);
44
- const isHeader = isHeaderFile(filePathAbsoluteFilesystem);
45
- const isPageConfigFile = !isValueFile;
46
- if (!isHeader && !isPageConfigFile) {
47
- return null;
48
- }
49
- (0, utils_js_1.assertWarning)(isPageConfigFile, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files should only be used for +config.h.js, see https://vike.dev/header-file`, { onlyOnce: true });
50
- // Remove the imports
51
- const res = (0, transformImportStatements_js_1.transformImportStatements)(codeOriginal, filePathToShowToUser2);
57
+ // Replace import statements with import strings
58
+ const res = (0, transformImports_js_1.transformImports)(codeOriginal, filePathToShowToUser2);
52
59
  if (res.noTransformation) {
53
60
  return null;
54
61
  }
55
62
  const { code, fileImportsTransformed } = res;
56
- if (!isHeader) {
63
+ if (!isHeaderFile(filePathAbsoluteFilesystem)) {
57
64
  const filePathCorrect = appendHeaderFileExtension(filePathToShowToUser2);
58
65
  (0, utils_js_1.assertWarning)(false, `Rename ${filePathToShowToUser2} to ${filePathCorrect}, see https://vike.dev/header-file`, {
59
66
  onlyOnce: true
@@ -61,7 +68,8 @@ function transformImports(codeOriginal, filePath, isValueFile) {
61
68
  }
62
69
  return { code, fileImportsTransformed };
63
70
  }
64
- async function transpileWithEsbuild(filePath, bundle, userRootDir) {
71
+ async function transpileWithEsbuild(filePath, userRootDir, importsAreTransformed, isValueFile) {
72
+ const isConfigFile = !isValueFile;
65
73
  const entryFilePath = filePath.filePathAbsoluteFilesystem;
66
74
  const entryFileDir = path_1.default.posix.dirname(entryFilePath);
67
75
  const options = {
@@ -77,22 +85,26 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
77
85
  'NEVER_EMITTED.js'),
78
86
  logLevel: 'silent',
79
87
  format: 'esm',
80
- bundle,
88
+ absWorkingDir: userRootDir,
89
+ // Disable tree-shaking to avoid dead-code elimination, so that unused imports aren't removed.
90
+ // Esbuild still sometimes removes unused imports because of TypeScript: https://github.com/evanw/esbuild/issues/3034
91
+ treeShaking: false,
81
92
  minify: false,
82
- metafile: bundle,
83
- absWorkingDir: userRootDir
93
+ metafile: isConfigFile,
94
+ // We cannot bundle imports that are meant to be transformed
95
+ bundle: !importsAreTransformed
84
96
  };
85
- if (bundle) {
86
- options.bundle = true;
97
+ // Track dependencies
98
+ if (isConfigFile) {
87
99
  options.packages = 'external';
88
100
  options.plugins = [
89
101
  {
90
- name: 'vike:import-hook',
102
+ name: 'vike:dependency-tracker',
91
103
  setup(b) {
92
104
  b.onLoad({ filter: /./ }, (args) => {
105
+ // We collect the dependency `args.path` in case the bulid fails (upon build error => error is thrown => no metafile)
93
106
  let { path } = args;
94
107
  path = (0, utils_js_1.toPosixPath)(path);
95
- // We collect the dependency args.path in case it fails to build (upon build error => error is thrown => no metafile)
96
108
  getVikeConfig_js_1.vikeConfigDependencies.add(path);
97
109
  return undefined;
98
110
  });
@@ -109,11 +121,6 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
109
121
  }
110
122
  ];
111
123
  }
112
- else {
113
- // Avoid dead-code elimination to ensure unused imports aren't removed.
114
- // Esbuild still sometimes removes unused imports because of TypeScript: https://github.com/evanw/esbuild/issues/3034
115
- options.treeShaking = false;
116
- }
117
124
  let result;
118
125
  try {
119
126
  result = await (0, esbuild_1.build)(options);
@@ -122,7 +129,8 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
122
129
  await formatBuildErr(err, filePath);
123
130
  throw err;
124
131
  }
125
- if (bundle) {
132
+ // Track dependencies
133
+ if (isConfigFile) {
126
134
  (0, utils_js_1.assert)(result.metafile);
127
135
  Object.keys(result.metafile.inputs).forEach((filePathRelative) => {
128
136
  filePathRelative = (0, utils_js_1.toPosixPath)(filePathRelative);
@@ -218,7 +226,7 @@ function assertImportsAreReExported(fileImportsTransformed, fileExports, filePat
218
226
  Object.values(exportedStrings).forEach((exportVal) => {
219
227
  if (typeof exportVal !== 'string')
220
228
  return;
221
- if (!(0, transformImportStatements_js_1.isImportData)(exportVal))
229
+ if (!(0, transformImports_js_1.isImportData)(exportVal))
222
230
  return;
223
231
  const importString = exportVal;
224
232
  fileImportsTransformed.forEach((fileImport) => {
@@ -256,6 +264,7 @@ function getExportedStrings(obj) {
256
264
  return exportedStrings;
257
265
  }
258
266
  function isHeaderFile(filePath) {
267
+ (0, utils_js_1.assertPosixPath)(filePath);
259
268
  const basenameParts = path_1.default.posix.basename(filePath).split('.');
260
269
  return basenameParts.includes('h');
261
270
  }
@@ -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.159-commit-71760c7';
5
+ const PROJECT_VERSION = '0.4.159-commit-0424983';
6
6
  exports.PROJECT_VERSION = PROJECT_VERSION;
7
7
  const projectInfo = {
8
8
  projectName: 'Vike',
@@ -7,7 +7,7 @@ import path from 'path';
7
7
  import { configDefinitionsBuiltIn, configDefinitionsBuiltInGlobal } from './getVikeConfig/configDefinitionsBuiltIn.js';
8
8
  import { getLocationId, getFilesystemRouteString, getFilesystemRouteDefinedBy, isInherited, sortAfterInheritanceOrder, isGlobalLocation, applyFilesystemRoutingRootEffect } from './getVikeConfig/filesystemRouting.js';
9
9
  import { isTmpFile, transpileAndExecuteFile } from './transpileAndExecuteFile.js';
10
- import { parseImportData } from './transformImportStatements.js';
10
+ import { parseImportData } from './transformImports.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';
@@ -85,7 +85,7 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
85
85
  let interfaceFilesByLocationId = {};
86
86
  // Config files
87
87
  await Promise.all(configFiles.map(async (filePath) => {
88
- const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, []);
88
+ const { configFile, extendsConfigs } = await loadConfigFile(filePath, userRootDir, [], false);
89
89
  const interfaceFile = getInterfaceFileFromConfigFile(configFile, false);
90
90
  const locationId = getLocationId(filePath.filePathAbsoluteVite);
91
91
  interfaceFilesByLocationId[locationId] = interfaceFilesByLocationId[locationId] ?? [];
@@ -840,10 +840,10 @@ function getConfigName(filePath) {
840
840
  return configName;
841
841
  }
842
842
  }
843
- async function loadConfigFile(configFilePath, userRootDir, visited) {
843
+ async function loadConfigFile(configFilePath, userRootDir, visited, isConfigOfExtension) {
844
844
  const { filePathAbsoluteFilesystem } = configFilePath;
845
845
  assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem);
846
- const { fileExports } = await transpileAndExecuteFile(configFilePath, false, userRootDir);
846
+ const { fileExports } = await transpileAndExecuteFile(configFilePath, false, userRootDir, isConfigOfExtension);
847
847
  const { extendsConfigs, extendsFilePaths } = await loadExtendsConfigs(fileExports, configFilePath, userRootDir, [
848
848
  ...visited,
849
849
  filePathAbsoluteFilesystem
@@ -885,7 +885,7 @@ async function loadExtendsConfigs(configFileExports, configFilePath, userRootDir
885
885
  });
886
886
  const extendsConfigs = [];
887
887
  await Promise.all(extendsConfigFiles.map(async (configFilePath) => {
888
- const result = await loadConfigFile(configFilePath, userRootDir, visited);
888
+ const result = await loadConfigFile(configFilePath, userRootDir, visited, true);
889
889
  extendsConfigs.push(result.configFile);
890
890
  extendsConfigs.push(...result.extendsConfigs);
891
891
  }));
@@ -1,15 +1,14 @@
1
- export { transformImportStatements };
1
+ export { transformImports };
2
2
  export { parseImportData };
3
3
  export { isImportData };
4
4
  export type { FileImport };
5
5
  export type { ImportData };
6
- export { isVikeRealImport };
7
6
  type FileImport = {
8
7
  importStatementCode: string;
9
8
  importString: string;
10
9
  importLocalName: string;
11
10
  };
12
- declare function transformImportStatements(code: string, filePathToShowToUser2: string): {
11
+ declare function transformImports(code: string, filePathToShowToUser2: string, skipWarnings?: true): {
13
12
  noTransformation: true;
14
13
  } | {
15
14
  noTransformation: false;
@@ -42,4 +41,3 @@ declare module 'estree' {
42
41
  end: number;
43
42
  }
44
43
  }
45
- declare function isVikeRealImport(code: string, posStart: number): boolean;
@@ -1,15 +1,15 @@
1
- export { transformImportStatements };
1
+ export { transformImports };
2
2
  export { parseImportData };
3
3
  export { isImportData };
4
- // For ./transformImportStatements.spec.ts
5
- export { isVikeRealImport };
6
4
  // Playground: https://github.com/brillout/acorn-playground
7
5
  // Import attributes support: https://github.com/acornjs/acorn/issues/983
8
6
  // - Isn't stage 4 yet: https://github.com/tc39/proposal-import-attributes
9
7
  import { parse } from 'acorn';
10
8
  import { assert, assertUsage, assertWarning, styleFileRE } from '../../../utils.js';
11
9
  import pc from '@brillout/picocolors';
12
- function transformImportStatements(code, filePathToShowToUser2) {
10
+ function transformImports(code, filePathToShowToUser2,
11
+ // For ./transformImports.spec.ts
12
+ skipWarnings) {
13
13
  const spliceOperations = [];
14
14
  const fileImportsTransformed = [];
15
15
  // Performance trick
@@ -23,9 +23,29 @@ function transformImportStatements(code, filePathToShowToUser2) {
23
23
  return;
24
24
  const importPath = node.source.value;
25
25
  assert(typeof importPath === 'string');
26
- const { start, end } = node;
27
- if (isVikeRealImport(code, end))
26
+ // - This doesn't work, to make it work we would need to run esbuild twice: esbuild for TypeScript to JavaScript => transformImports() => esbuild for bundling.
27
+ // - Or we use an esbuild plugin to apply transformImports(). Maybe we can completely skip the need for acorn?
28
+ // - ?real breaks TypeScript, and TypeScript isn't working on supporting query params: https://github.com/microsoft/TypeScript/issues/10988#issuecomment-867135453
29
+ // - Import attributes would be the best.
30
+ // - But it only works with Node.js >=21: https://nodejs.org/api/esm.html#import-attributes
31
+ // - But it's probably ok to tell users "to use real imports you need Node.js 21 or above".
32
+ // - It seems to work well with the latest TypeScript versions: TypeScript doesn't complain upon `with { type: 'unknown-to-typescript' }` and go-to-definition & types are preserved.
33
+ // - Esbuid seems to support it: https://esbuild.github.io/plugins/#on-load-arguments:~:text=This%20contains%20a%20map%20of%20the%20import%20attributes%20that
34
+ // - acorn supports it over an acorn plugin: https://github.com/acornjs/acorn/issues/983
35
+ // - Maybe we can use an esbuild plugin instead of acorn to apply transformImports()?
36
+ // - Using a magic comment `// @vike-real-import` is tricky:
37
+ // - Esbuild removes comments: https://github.com/evanw/esbuild/issues/1439#issuecomment-877656182
38
+ // - Using source maps to track these magic comments is brittle (source maps can easily break)
39
+ if (importPath.endsWith('?real')) {
40
+ const { start, end } = node.source;
41
+ spliceOperations.push({
42
+ start,
43
+ end,
44
+ replacement: importPath.slice(0, -1 * '?real'.length)
45
+ });
28
46
  return;
47
+ }
48
+ const { start, end } = node;
29
49
  const importStatementCode = code.slice(start, end);
30
50
  // No variable imported
31
51
  if (node.specifiers.length === 0) {
@@ -41,10 +61,12 @@ function transformImportStatements(code, filePathToShowToUser2) {
41
61
  `As explained in https://vike.dev/header-file the following import in ${filePathToShowToUser2} has no effect:`,
42
62
  quote
43
63
  ].join('\n');
44
- if (!isWarning) {
45
- assertUsage(false, errMsg);
64
+ if (!skipWarnings) {
65
+ if (!isWarning) {
66
+ assertUsage(false, errMsg);
67
+ }
68
+ assertWarning(false, errMsg, { onlyOnce: true });
46
69
  }
47
- assertWarning(false, errMsg, { onlyOnce: true });
48
70
  }
49
71
  let replacement = '';
50
72
  node.specifiers.forEach((specifier) => {
@@ -146,7 +168,7 @@ function spliceMany(str, operations) {
146
168
  .join('');
147
169
  endPrev = end;
148
170
  });
149
- strMod += str.slice(endPrev, str.length - 1);
171
+ strMod += str.slice(endPrev, str.length);
150
172
  return strMod;
151
173
  }
152
174
  function indent(str) {
@@ -155,10 +177,3 @@ function indent(str) {
155
177
  .map((s) => ` ${s}`)
156
178
  .join('\n');
157
179
  }
158
- function isVikeRealImport(code, posStart) {
159
- let posEnd = code.indexOf('\n', posStart);
160
- if (posEnd === -1)
161
- posEnd = code.length;
162
- const lineEnd = code.slice(posStart, posEnd);
163
- return lineEnd.includes('@vike-real-import');
164
- }
@@ -4,7 +4,7 @@ export { getConfigExecutionErrorIntroMsg as getConfigExecutionErrorIntroMsg };
4
4
  export { isTmpFile };
5
5
  import 'source-map-support/register.js';
6
6
  import type { FilePathResolved } from '../../../../../shared/page-configs/PageConfig.js';
7
- declare function transpileAndExecuteFile(filePath: FilePathResolved, isValueFile: boolean, userRootDir: string): Promise<{
7
+ declare function transpileAndExecuteFile(filePath: FilePathResolved, isValueFile: boolean, userRootDir: string, isConfigOfExtension?: boolean): Promise<{
8
8
  fileExports: Record<string, unknown>;
9
9
  }>;
10
10
  declare function getConfigBuildErrorFormatted(err: unknown): null | string;
@@ -8,49 +8,56 @@ import path from 'path';
8
8
  import pc from '@brillout/picocolors';
9
9
  import { import_ } from '@brillout/import';
10
10
  import { assertPosixPath, getRandomId, assertIsNotProductionRuntime, assert, unique, assertWarning, isObject, toPosixPath } from '../../../utils.js';
11
- import { isImportData, transformImportStatements } from './transformImportStatements.js';
11
+ import { isImportData, transformImports } from './transformImports.js';
12
12
  import { vikeConfigDependencies } from './getVikeConfig.js';
13
13
  import 'source-map-support/register.js';
14
14
  import { getConfigFileExport } from './getConfigFileExport.js';
15
15
  assertIsNotProductionRuntime();
16
- async function transpileAndExecuteFile(filePath, isValueFile, userRootDir) {
17
- const { code, fileImportsTransformed } = await transpileFile(filePath, isValueFile, userRootDir);
16
+ async function transpileAndExecuteFile(filePath, isValueFile, userRootDir, isConfigOfExtension = false) {
17
+ const { code, fileImportsTransformed } = await transpileFile(filePath, isValueFile, userRootDir, isConfigOfExtension);
18
18
  const { fileExports } = await executeFile(filePath, code, fileImportsTransformed, isValueFile);
19
19
  return { fileExports };
20
20
  }
21
- async function transpileFile(filePath, isValueFile, userRootDir) {
21
+ async function transpileFile(filePath, isValueFile, userRootDir, isConfigOfExtension) {
22
22
  const { filePathAbsoluteFilesystem } = filePath;
23
+ const filePathToShowToUser2 = getFilePathToShowToUser2(filePath);
23
24
  assertPosixPath(filePathAbsoluteFilesystem);
24
25
  vikeConfigDependencies.add(filePathAbsoluteFilesystem);
25
- let code = await transpileWithEsbuild(filePath, isValueFile, userRootDir);
26
+ const importsAreTransformed = !isConfigOfExtension && !isValueFile;
27
+ let code = await transpileWithEsbuild(filePath, userRootDir, importsAreTransformed, isValueFile);
26
28
  let fileImportsTransformed = null;
27
- {
28
- const res = transformImports(code, filePath, isValueFile);
29
+ if (importsAreTransformed) {
30
+ const res = transformImports_(code, filePath);
29
31
  if (res) {
30
32
  code = res.code;
31
33
  fileImportsTransformed = res.fileImportsTransformed;
32
34
  }
33
35
  }
36
+ else {
37
+ if (isHeaderFile(filePathAbsoluteFilesystem)) {
38
+ if (isValueFile) {
39
+ assertWarning(false, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files only apply to +config.h.js, see https://vike.dev/header-file`, { onlyOnce: true });
40
+ }
41
+ else if (isConfigOfExtension) {
42
+ assertWarning(false, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files don't apply to the config files of extensions`, { onlyOnce: true });
43
+ }
44
+ else {
45
+ assert(false);
46
+ }
47
+ }
48
+ }
34
49
  return { code, fileImportsTransformed };
35
50
  }
36
- function transformImports(codeOriginal, filePath, isValueFile) {
37
- // Do we need to remove the imports?
51
+ function transformImports_(codeOriginal, filePath) {
38
52
  const { filePathAbsoluteFilesystem } = filePath;
39
53
  const filePathToShowToUser2 = getFilePathToShowToUser2(filePath);
40
- assertPosixPath(filePathAbsoluteFilesystem);
41
- const isHeader = isHeaderFile(filePathAbsoluteFilesystem);
42
- const isPageConfigFile = !isValueFile;
43
- if (!isHeader && !isPageConfigFile) {
44
- return null;
45
- }
46
- assertWarning(isPageConfigFile, `${filePathToShowToUser2} is a JavaScript header file (.h.js), but JavaScript header files should only be used for +config.h.js, see https://vike.dev/header-file`, { onlyOnce: true });
47
- // Remove the imports
48
- const res = transformImportStatements(codeOriginal, filePathToShowToUser2);
54
+ // Replace import statements with import strings
55
+ const res = transformImports(codeOriginal, filePathToShowToUser2);
49
56
  if (res.noTransformation) {
50
57
  return null;
51
58
  }
52
59
  const { code, fileImportsTransformed } = res;
53
- if (!isHeader) {
60
+ if (!isHeaderFile(filePathAbsoluteFilesystem)) {
54
61
  const filePathCorrect = appendHeaderFileExtension(filePathToShowToUser2);
55
62
  assertWarning(false, `Rename ${filePathToShowToUser2} to ${filePathCorrect}, see https://vike.dev/header-file`, {
56
63
  onlyOnce: true
@@ -58,7 +65,8 @@ function transformImports(codeOriginal, filePath, isValueFile) {
58
65
  }
59
66
  return { code, fileImportsTransformed };
60
67
  }
61
- async function transpileWithEsbuild(filePath, bundle, userRootDir) {
68
+ async function transpileWithEsbuild(filePath, userRootDir, importsAreTransformed, isValueFile) {
69
+ const isConfigFile = !isValueFile;
62
70
  const entryFilePath = filePath.filePathAbsoluteFilesystem;
63
71
  const entryFileDir = path.posix.dirname(entryFilePath);
64
72
  const options = {
@@ -74,22 +82,26 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
74
82
  'NEVER_EMITTED.js'),
75
83
  logLevel: 'silent',
76
84
  format: 'esm',
77
- bundle,
85
+ absWorkingDir: userRootDir,
86
+ // Disable tree-shaking to avoid dead-code elimination, so that unused imports aren't removed.
87
+ // Esbuild still sometimes removes unused imports because of TypeScript: https://github.com/evanw/esbuild/issues/3034
88
+ treeShaking: false,
78
89
  minify: false,
79
- metafile: bundle,
80
- absWorkingDir: userRootDir
90
+ metafile: isConfigFile,
91
+ // We cannot bundle imports that are meant to be transformed
92
+ bundle: !importsAreTransformed
81
93
  };
82
- if (bundle) {
83
- options.bundle = true;
94
+ // Track dependencies
95
+ if (isConfigFile) {
84
96
  options.packages = 'external';
85
97
  options.plugins = [
86
98
  {
87
- name: 'vike:import-hook',
99
+ name: 'vike:dependency-tracker',
88
100
  setup(b) {
89
101
  b.onLoad({ filter: /./ }, (args) => {
102
+ // We collect the dependency `args.path` in case the bulid fails (upon build error => error is thrown => no metafile)
90
103
  let { path } = args;
91
104
  path = toPosixPath(path);
92
- // We collect the dependency args.path in case it fails to build (upon build error => error is thrown => no metafile)
93
105
  vikeConfigDependencies.add(path);
94
106
  return undefined;
95
107
  });
@@ -106,11 +118,6 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
106
118
  }
107
119
  ];
108
120
  }
109
- else {
110
- // Avoid dead-code elimination to ensure unused imports aren't removed.
111
- // Esbuild still sometimes removes unused imports because of TypeScript: https://github.com/evanw/esbuild/issues/3034
112
- options.treeShaking = false;
113
- }
114
121
  let result;
115
122
  try {
116
123
  result = await build(options);
@@ -119,7 +126,8 @@ async function transpileWithEsbuild(filePath, bundle, userRootDir) {
119
126
  await formatBuildErr(err, filePath);
120
127
  throw err;
121
128
  }
122
- if (bundle) {
129
+ // Track dependencies
130
+ if (isConfigFile) {
123
131
  assert(result.metafile);
124
132
  Object.keys(result.metafile.inputs).forEach((filePathRelative) => {
125
133
  filePathRelative = toPosixPath(filePathRelative);
@@ -250,6 +258,7 @@ function getExportedStrings(obj) {
250
258
  return exportedStrings;
251
259
  }
252
260
  function isHeaderFile(filePath) {
261
+ assertPosixPath(filePath);
253
262
  const basenameParts = path.posix.basename(filePath).split('.');
254
263
  return basenameParts.includes('h');
255
264
  }
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- declare const PROJECT_VERSION: "0.4.159-commit-71760c7";
3
+ declare const PROJECT_VERSION: "0.4.159-commit-0424983";
4
4
  declare const projectInfo: {
5
5
  projectName: "Vike";
6
- projectVersion: "0.4.159-commit-71760c7";
6
+ projectVersion: "0.4.159-commit-0424983";
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.159-commit-71760c7';
4
+ const PROJECT_VERSION = '0.4.159-commit-0424983';
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.159-commit-71760c7",
3
+ "version": "0.4.159-commit-0424983",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",