vike 0.4.259 → 0.4.260-commit-2e7fb2a
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.
- package/AGENTS.md +3 -0
- package/README.md +2 -0
- package/dist/client/runtime-client-routing/renderPageClient.js +1 -1
- package/dist/client/shared/getJsonSerializedInHtml.js +1 -10
- package/dist/node/api/build.js +6 -6
- package/dist/node/api/dev.d.ts +2 -10
- package/dist/node/api/dev.js +5 -52
- package/dist/node/api/prepareViteApiCall.d.ts +1 -1
- package/dist/node/api/prepareViteApiCall.js +2 -2
- package/dist/node/api/prerender.js +2 -2
- package/dist/node/api/preview.d.ts +2 -2
- package/dist/node/api/preview.js +15 -16
- package/dist/node/api/{resolveViteConfigFromUser.d.ts → resolveViteConfigUser.d.ts} +5 -5
- package/dist/node/api/{resolveViteConfigFromUser.js → resolveViteConfigUser.js} +100 -69
- package/dist/node/api/startupLog.d.ts +4 -0
- package/dist/node/api/{getStartupLogFirstLine.js → startupLog.js} +14 -1
- package/dist/node/api/types.d.ts +9 -0
- package/dist/node/cli/entry.js +1 -5
- package/dist/node/cli/parseCli.js +26 -12
- package/dist/node/createDevMiddleware.js +2 -2
- package/dist/node/prerender/runPrerender.d.ts +8 -2
- package/dist/node/prerender/runPrerender.js +3 -1
- package/dist/node/prerender/runPrerenderEntry.js +2 -2
- package/dist/node/vite/index.js +2 -2
- package/dist/node/vite/plugins/build/handleAssetsManifest.d.ts +2 -6
- package/dist/node/vite/plugins/build/handleAssetsManifest.js +16 -9
- package/dist/node/vite/plugins/build/pluginBuildApp.js +10 -5
- package/dist/node/vite/plugins/build/pluginBuildConfig.d.ts +6 -1
- package/dist/node/vite/plugins/build/pluginBuildConfig.js +13 -11
- package/dist/node/vite/plugins/build/pluginDistFileNames.js +1 -6
- package/dist/node/vite/plugins/build/pluginModuleBanner.js +2 -4
- package/dist/node/vite/plugins/pluginCommon.d.ts +1 -1
- package/dist/node/vite/plugins/pluginCommon.js +15 -7
- package/dist/node/vite/plugins/pluginDev/autoAddVikeSkill.d.ts +3 -0
- package/dist/node/vite/plugins/pluginDev/autoAddVikeSkill.js +174 -0
- package/dist/node/vite/plugins/pluginDev/optimizeDeps.js +67 -31
- package/dist/node/vite/plugins/pluginDev.js +17 -0
- package/dist/node/vite/plugins/pluginStripPointerImportAttribute.js +31 -10
- package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFilePageEntry.js +5 -7
- package/dist/node/vite/plugins/pluginVirtualFiles/getConfigValueSourcesRelevant.d.ts +2 -2
- package/dist/node/vite/plugins/pluginVirtualFiles.js +1 -1
- package/dist/node/vite/shared/addSsrMiddleware.js +1 -1
- package/dist/node/vite/shared/getMagicString.d.ts +1 -1
- package/dist/node/vite/shared/getMagicString.js +3 -0
- package/dist/node/vite/shared/isVite8OrAbove.d.ts +4 -0
- package/dist/node/vite/shared/isVite8OrAbove.js +9 -0
- package/dist/node/vite/shared/isViteCli.d.ts +9 -4
- package/dist/node/vite/shared/isViteCli.js +24 -4
- package/dist/node/vite/shared/loggerDev.js +6 -5
- package/dist/node/vite/shared/loggerVite.js +3 -2
- package/dist/node/vite/shared/resolveVikeConfigInternal/assertExtensions.d.ts +3 -1
- package/dist/node/vite/shared/resolveVikeConfigInternal/assertExtensions.js +6 -5
- package/dist/node/vite/shared/resolveVikeConfigInternal/{crawlPlusFilePaths.d.ts → crawlPlusFiles.d.ts} +2 -2
- package/dist/node/vite/shared/resolveVikeConfigInternal/crawlPlusFiles.js +71 -0
- package/dist/node/vite/shared/resolveVikeConfigInternal/{getPlusFilesByLocationId.d.ts → getPlusFiles.d.ts} +5 -3
- package/dist/node/vite/shared/resolveVikeConfigInternal/{getPlusFilesByLocationId.js → getPlusFiles.js} +18 -17
- package/dist/node/vite/shared/resolveVikeConfigInternal/loadFileAtConfigTime.d.ts +1 -1
- package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.d.ts +15 -15
- package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.js +19 -0
- package/dist/node/vite/shared/resolveVikeConfigInternal.d.ts +19 -4
- package/dist/node/vite/shared/resolveVikeConfigInternal.js +217 -76
- package/dist/server/runtime/globalContext.js +4 -1
- package/dist/server/runtime/renderPageServer/createPageContextServer.d.ts +12 -3
- package/dist/server/runtime/renderPageServer/html/injectAssets/getHtmlTags.js +2 -3
- package/dist/server/runtime/renderPageServer/html/injectAssets/injectHtmlTags.js +3 -1
- package/dist/server/runtime/renderPageServer/html/serializeContext.js +5 -10
- package/dist/server/runtime/renderPageServer/loadPageConfigsLazyServerSide.d.ts +8 -2
- package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.d.ts +32 -8
- package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.js +1 -1
- package/dist/server/runtime/renderPageServer.d.ts +8 -2
- package/dist/server/runtime/renderPageServer.js +6 -4
- package/dist/shared-server-client/page-configs/serialize/serializeConfigValues.d.ts +3 -3
- package/dist/shared-server-client/page-configs/serialize/serializeConfigValues.js +8 -1
- package/dist/types/Config.d.ts +54 -6
- package/dist/types/PageConfig.d.ts +12 -10
- package/dist/types/PageContext.d.ts +8 -3
- package/dist/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/utils/PROJECT_VERSION.js +1 -1
- package/dist/utils/assert.d.ts +2 -0
- package/dist/utils/assert.js +8 -8
- package/dist/utils/assertViteVersion.js +1 -1
- package/dist/utils/crawlFiles/ignorePatternsBuiltIn.d.ts +1 -0
- package/dist/{node/vite/shared/resolveVikeConfigInternal/crawlPlusFilePaths → utils/crawlFiles}/ignorePatternsBuiltIn.js +1 -1
- package/dist/utils/crawlFiles.d.ts +21 -0
- package/dist/utils/crawlFiles.js +195 -0
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +1 -0
- package/dist/{node/vite/shared → utils}/getEnvVarObject.d.ts +0 -1
- package/dist/{node/vite/shared → utils}/getEnvVarObject.js +4 -3
- package/dist/utils/getViteRPC.js +1 -1
- package/dist/utils/objectMap.d.ts +2 -0
- package/dist/utils/objectMap.js +4 -0
- package/dist/utils/parseNpmPackage.js +4 -1
- package/dist/utils/pick.d.ts +1 -1
- package/dist/utils/setTimeoutUnref.d.ts +2 -0
- package/dist/utils/setTimeoutUnref.js +11 -0
- package/package.json +19 -21
- package/dist/node/api/getStartupLogFirstLine.d.ts +0 -7
- package/dist/node/vite/shared/resolveVikeConfigInternal/crawlPlusFilePaths/ignorePatternsBuiltIn.d.ts +0 -2
- package/dist/node/vite/shared/resolveVikeConfigInternal/crawlPlusFilePaths.js +0 -258
- package/dist/server/__internal/vite.d.ts +0 -2
- package/dist/server/__internal/vite.js +0 -2
- package/dist/server/runtime/renderPageServer/html/injectAssets/sanitizeJson.d.ts +0 -4
- package/dist/server/runtime/renderPageServer/html/injectAssets/sanitizeJson.js +0 -7
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export { autoAddVikeSkill };
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import pc from '@brillout/picocolors';
|
|
7
|
+
import { assertInfo, assertUsage } from '../../../../utils/assert.js';
|
|
8
|
+
import { assertKeys } from '../../../../utils/assertKeys.js';
|
|
9
|
+
import { crawlFiles } from '../../../../utils/crawlFiles.js';
|
|
10
|
+
import { getGlobalObject } from '../../../../utils/getGlobalObject.js';
|
|
11
|
+
import { getVikeConfigError } from '../../../../shared-server-node/getVikeConfigError.js';
|
|
12
|
+
import { isArrayOfStrings } from '../../../../utils/isArrayOfStrings.js';
|
|
13
|
+
import { isFilePathAbsoluteFilesystem } from '../../../../utils/isFilePathAbsoluteFilesystem.js';
|
|
14
|
+
import { isObject } from '../../../../utils/isObject.js';
|
|
15
|
+
import { unique } from '../../../../utils/unique.js';
|
|
16
|
+
import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
|
|
17
|
+
import '../../assertEnvVite.js';
|
|
18
|
+
const execFileA = promisify(execFile);
|
|
19
|
+
const importMetaUrl = import.meta.url;
|
|
20
|
+
const globalObject = getGlobalObject('autoAddVikeSkill.ts', {
|
|
21
|
+
alreadyDone: false,
|
|
22
|
+
});
|
|
23
|
+
const skillPathInsideSkillsDir = 'vike/SKILL.md';
|
|
24
|
+
const skillFileContent = `---
|
|
25
|
+
name: "vike"
|
|
26
|
+
description: "Vike documentation index — a compact overview of Vike's docs. Consider consulting it, e.g. when using uncommon Vike APIs or when stuck on a Vike problem."
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
See https://vike.dev/llms.txt
|
|
30
|
+
`;
|
|
31
|
+
const commitMessage = (isUpdate) => `${isUpdate ? 'Update' : 'Add'} Vike skill — see https://vike.dev/ai#skill`;
|
|
32
|
+
// Automatically add vike/SKILL.md to skills/ directories (e.g. .claude/skills/ and .agents/skills/) of the user's Git repository (and Git-commit it) — so that AI agents (Claude Code, Codex, Cursor, Gemini CLI, ...) automatically pick it up.
|
|
33
|
+
// https://vike.dev/ai#skill
|
|
34
|
+
async function autoAddVikeSkill(userRootDir) {
|
|
35
|
+
try {
|
|
36
|
+
await autoAddVikeSkillUnsafe(userRootDir);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
// Show the error without breaking the dev server. (Expected situations don't throw — e.g. Git missing is handled gracefully.)
|
|
40
|
+
console.error(err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function autoAddVikeSkillUnsafe(userRootDir) {
|
|
44
|
+
if (globalObject.alreadyDone)
|
|
45
|
+
return;
|
|
46
|
+
// Skip CI environments: the skill file is meant to be added from the machine of an app developer.
|
|
47
|
+
if (process.env.CI)
|
|
48
|
+
return;
|
|
49
|
+
// Skip if Vike isn't inside node_modules/ (e.g. when Vike is linked, such as when running an example of the Vike monorepo).
|
|
50
|
+
if (!importMetaUrl.includes('node_modules/'))
|
|
51
|
+
return;
|
|
52
|
+
const vikeConfig = await getVikeConfigInternal();
|
|
53
|
+
// Maybe the user disabled the feature in a config file that currently has an error => retry later (Vite restarts upon config changes).
|
|
54
|
+
if (getVikeConfigError())
|
|
55
|
+
return;
|
|
56
|
+
const configValue = getConfigValueAiSkill(vikeConfig);
|
|
57
|
+
if (configValue === false)
|
|
58
|
+
return;
|
|
59
|
+
globalObject.alreadyDone = true;
|
|
60
|
+
const res = await addAiSkill(userRootDir, {
|
|
61
|
+
// true (default) => add the skill file to every existing skills directory (`**/skills/*/SKILL.md`)
|
|
62
|
+
skillsDirs: configValue === true ? undefined : configValue,
|
|
63
|
+
});
|
|
64
|
+
if (!res)
|
|
65
|
+
return;
|
|
66
|
+
assertInfo(false, `${res.isUpdate ? 'Updated' : 'Created'}${res.isCommitted ? ' and Git-committed' : ''} ${res.files
|
|
67
|
+
.map((f) => pc.cyan(f.filePathRelative))
|
|
68
|
+
.join(', ')} — see https://vike.dev/ai#skill`, { onlyOnce: false });
|
|
69
|
+
}
|
|
70
|
+
// https://vike.dev/ai#skill
|
|
71
|
+
function getConfigValueAiSkill(vikeConfig) {
|
|
72
|
+
const configAi = vikeConfig.config.ai;
|
|
73
|
+
if (configAi === undefined)
|
|
74
|
+
return true;
|
|
75
|
+
assertUsage(isObject(configAi), `Setting ${pc.cyan('ai')} should be an object`);
|
|
76
|
+
assertKeys(configAi, ['skill'], `Setting ${pc.cyan('ai')}:`);
|
|
77
|
+
const skill = configAi.skill;
|
|
78
|
+
if (skill === undefined || skill === true)
|
|
79
|
+
return true;
|
|
80
|
+
if (skill === false)
|
|
81
|
+
return false;
|
|
82
|
+
assertUsage(isArrayOfStrings(skill), `Setting ${pc.cyan('ai.skill')} should be a boolean or a list of skills directories (e.g. ${pc.cyan("['.claude/skills', '.agents/skills']")})`);
|
|
83
|
+
return skill.map((skillsDir) => {
|
|
84
|
+
assertUsage(skillsDir !== '' && !isFilePathAbsoluteFilesystem(skillsDir), `Setting ${pc.cyan('ai.skill')} entries should be paths relative to the root directory of your app's Git repository (e.g. ${pc.cyan("'.claude/skills'")})`);
|
|
85
|
+
// Normalize: remove trailing slashes
|
|
86
|
+
return skillsDir.replace(/\/+$/, '');
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async function addAiSkill(userRootDir, { skillsDirs }) {
|
|
90
|
+
// Skip if Git isn't installed
|
|
91
|
+
if ('err' in (await runGitCommand(['--version'], userRootDir)))
|
|
92
|
+
return null;
|
|
93
|
+
// Skip if the app isn't inside a Git repository
|
|
94
|
+
const resGitRootDir = await runGitCommand(['rev-parse', '--show-toplevel'], userRootDir);
|
|
95
|
+
if ('err' in resGitRootDir)
|
|
96
|
+
return null;
|
|
97
|
+
const gitRootDir = resGitRootDir.stdout.trim();
|
|
98
|
+
if (!gitRootDir)
|
|
99
|
+
return null;
|
|
100
|
+
// By default, the skill file is only added to the skills directories that already exist — we don't want to add files to the repositories of users who don't use skills.
|
|
101
|
+
skillsDirs ?? (skillsDirs = await discoverSkillsDirs(gitRootDir));
|
|
102
|
+
if (skillsDirs.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
const files = [];
|
|
105
|
+
for (const skillsDir of skillsDirs) {
|
|
106
|
+
const filePathRelative = `${skillsDir}/${skillPathInsideSkillsDir}`;
|
|
107
|
+
const filePathAbsolute = path.join(gitRootDir, ...filePathRelative.split('/'));
|
|
108
|
+
// Skip if the skill file is already up-to-date
|
|
109
|
+
const contentCurrent = await fs.readFile(filePathAbsolute, 'utf8').catch(() => null);
|
|
110
|
+
if (contentCurrent === skillFileContent)
|
|
111
|
+
continue;
|
|
112
|
+
const isUpdate = contentCurrent !== null;
|
|
113
|
+
await fs.mkdir(path.dirname(filePathAbsolute), { recursive: true });
|
|
114
|
+
await fs.writeFile(filePathAbsolute, skillFileContent, 'utf8');
|
|
115
|
+
files.push({ filePathAbsolute, filePathRelative, isUpdate });
|
|
116
|
+
}
|
|
117
|
+
if (files.length === 0)
|
|
118
|
+
return null;
|
|
119
|
+
const isCommitted = await gitCommit(gitRootDir, files);
|
|
120
|
+
return { files, isUpdate: files.some((f) => f.isUpdate), isCommitted };
|
|
121
|
+
}
|
|
122
|
+
// Discover the skills directories of the user's Git repository, following the Agent Skills convention `**/skills/*/SKILL.md` (https://agentskills.io) — e.g. .claude/skills/ (Claude Code) and .agents/skills/ (Codex, Gemini CLI, Cursor, ...).
|
|
123
|
+
async function discoverSkillsDirs(gitRootDir) {
|
|
124
|
+
const files = await crawlFiles({
|
|
125
|
+
filePattern: '**/skills/*/SKILL',
|
|
126
|
+
fileExtension: ['md'],
|
|
127
|
+
cwd: gitRootDir,
|
|
128
|
+
// Skills directories usually live inside dot directories (e.g. .claude/ and .agents/)
|
|
129
|
+
dot: true,
|
|
130
|
+
// Most apps don't contain any skills directory — when Git doesn't know about any skill file, we don't want to crawl the app's entire directory tree upon every dev start.
|
|
131
|
+
globFallback: false,
|
|
132
|
+
});
|
|
133
|
+
const skillsDirs = unique(files.map((filePath) => path.posix.dirname(path.posix.dirname(filePath)))).sort();
|
|
134
|
+
return skillsDirs;
|
|
135
|
+
}
|
|
136
|
+
async function gitCommit(gitRootDir, files) {
|
|
137
|
+
// Don't Git-commit the skill files that the user chose to .gitignore — `$ git check-ignore` succeeds if the file is ignored
|
|
138
|
+
const filesToCommit = [];
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
const resCheckIgnore = await runGitCommand(['check-ignore', '-q', '--', file.filePathRelative], gitRootDir);
|
|
141
|
+
if ('err' in resCheckIgnore)
|
|
142
|
+
filesToCommit.push(file);
|
|
143
|
+
}
|
|
144
|
+
if (filesToCommit.length === 0)
|
|
145
|
+
return false;
|
|
146
|
+
const filePaths = filesToCommit.map((f) => f.filePathRelative);
|
|
147
|
+
const resAdd = await runGitCommand(['add', '--', ...filePaths], gitRootDir);
|
|
148
|
+
if ('err' in resAdd)
|
|
149
|
+
return false;
|
|
150
|
+
const isUpdate = filesToCommit.some((f) => f.isUpdate);
|
|
151
|
+
const resCommit = await runGitCommand([
|
|
152
|
+
'commit',
|
|
153
|
+
// Skip Git hooks (e.g. slow or failing pre-commit hooks)
|
|
154
|
+
'--no-verify',
|
|
155
|
+
'-m',
|
|
156
|
+
commitMessage(isUpdate),
|
|
157
|
+
// Only commit the skill files — never commit files staged by the user
|
|
158
|
+
'--',
|
|
159
|
+
...filePaths,
|
|
160
|
+
], gitRootDir);
|
|
161
|
+
return !('err' in resCommit);
|
|
162
|
+
}
|
|
163
|
+
// Run a Git command — doesn't throw: it returns `{ err }` upon failure.
|
|
164
|
+
async function runGitCommand(args, cwd) {
|
|
165
|
+
let stdout;
|
|
166
|
+
try {
|
|
167
|
+
const res = await execFileA('git', args, { cwd });
|
|
168
|
+
stdout = res.stdout.toString();
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
return { err };
|
|
172
|
+
}
|
|
173
|
+
return { stdout };
|
|
174
|
+
}
|
|
@@ -3,6 +3,7 @@ export { resolveOptimizeDeps };
|
|
|
3
3
|
import { findPageFiles } from '../../shared/findPageFiles.js';
|
|
4
4
|
import { assert } from '../../../../utils/assert.js';
|
|
5
5
|
import { createDebug } from '../../../../utils/debug.js';
|
|
6
|
+
import { deepEqual } from '../../../../utils/deepEqual.js';
|
|
6
7
|
import { isArray } from '../../../../utils/isArray.js';
|
|
7
8
|
import { isFilePathAbsoluteFilesystem } from '../../../../utils/isFilePathAbsoluteFilesystem.js';
|
|
8
9
|
import { assertImportIsNpmPackage, getNpmPackageName } from '../../../../utils/parseNpmPackage.js';
|
|
@@ -24,8 +25,12 @@ const LATE_DISCOVERED = [
|
|
|
24
25
|
// Workaround for https://github.com/vikejs/vike/issues/2823#issuecomment-3514325487
|
|
25
26
|
'@compiled/react/runtime',
|
|
26
27
|
];
|
|
27
|
-
// TO-DO/eventually: remove this
|
|
28
|
-
//
|
|
28
|
+
// TO-DO/eventually: remove this workaround using following plan:
|
|
29
|
+
// 1. Remove `include: ["vike > @brillout/require-shim"]` from vike-photon
|
|
30
|
+
// https://github.com/vikejs/vike-photon/blob/e11edb617ae44da6c1748222c387b10bf3fa5495/packages/vike-photon/src/plugin/plugins/configPlugin.ts#L16-L17
|
|
31
|
+
// 2. Release new vike-photon version
|
|
32
|
+
// 2. Remove this workaround
|
|
33
|
+
// Even though Vike doesn't use @brillout/require-shim anymore, it's still needed because vike-photon adds @brillout/require-shim to optimizeDeps.include which leads to this error:
|
|
29
34
|
// ```
|
|
30
35
|
// [11:32:49.768][/test/photon-vercel/.test-dev.test.ts][pnpm run dev][stderr] Failed to resolve dependency: vike > @brillout/require-shim, present in ssr 'optimizeDeps.include'
|
|
31
36
|
// ```
|
|
@@ -70,9 +75,9 @@ const optimizeDeps = {
|
|
|
70
75
|
// - Make server environments inherit from ssr.optimizeDeps (it isn't the case by default)
|
|
71
76
|
async function resolveOptimizeDeps(config) {
|
|
72
77
|
const vikeConfig = await getVikeConfigInternal();
|
|
73
|
-
const { _pageConfigs: pageConfigs } = vikeConfig;
|
|
78
|
+
const { _pageConfigs: pageConfigs, _pageConfigGlobal: pageConfigGlobal } = vikeConfig;
|
|
74
79
|
// Retrieve user's + files (i.e. Vike entries)
|
|
75
|
-
const { entriesClient, entriesServer, includeClient, includeServer } = await getPageDeps(config, pageConfigs);
|
|
80
|
+
const { entriesClient, entriesServer, includeClient, includeServer } = await getPageDeps(config, pageConfigs, pageConfigGlobal);
|
|
76
81
|
// Add late discovered dependencies, if they exist
|
|
77
82
|
LATE_DISCOVERED.forEach((dep) => {
|
|
78
83
|
const userRootDir = config.root;
|
|
@@ -114,18 +119,19 @@ async function resolveOptimizeDeps(config) {
|
|
|
114
119
|
env.optimizeDeps.entries = remove(env.optimizeDeps.entries ?? []);
|
|
115
120
|
}
|
|
116
121
|
// Debug
|
|
117
|
-
if (debug.isActivated)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
if (debug.isActivated) {
|
|
123
|
+
const envs = {};
|
|
124
|
+
for (const envName in config.environments) {
|
|
125
|
+
const env = config.environments[envName];
|
|
126
|
+
envs[`config.environments.${envName}.optimizeDeps.entries`] = env.optimizeDeps.entries;
|
|
127
|
+
envs[`config.environments.${envName}.optimizeDeps.include`] = env.optimizeDeps.include;
|
|
128
|
+
envs[`config.environments.${envName}.optimizeDeps.exclude`] = env.optimizeDeps.exclude;
|
|
129
|
+
}
|
|
130
|
+
debug('optimizeDeps', envs);
|
|
131
|
+
assertEnvsInSyncWithLegacy(config);
|
|
132
|
+
}
|
|
127
133
|
}
|
|
128
|
-
async function getPageDeps(config, pageConfigs) {
|
|
134
|
+
async function getPageDeps(config, pageConfigs, pageConfigGlobal) {
|
|
129
135
|
let entriesClient = [];
|
|
130
136
|
let entriesServer = [];
|
|
131
137
|
let includeClient = [];
|
|
@@ -158,6 +164,14 @@ async function getPageDeps(config, pageConfigs) {
|
|
|
158
164
|
includeServer.push(e);
|
|
159
165
|
}
|
|
160
166
|
};
|
|
167
|
+
const addEntryOrInclude = (filePath, isForClientSide, definedAt) => {
|
|
168
|
+
if (filePath.filePathAbsoluteUserRootDir !== null) {
|
|
169
|
+
addEntry(filePath.filePathAbsoluteFilesystem, isForClientSide, definedAt);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
addInclude(filePath.importPathAbsolute, isForClientSide, definedAt);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
161
175
|
const isExcluded = (e, isForClientSide, definedAt) => {
|
|
162
176
|
const exclude = isForClientSide ? config.optimizeDeps.exclude : config.ssr.optimizeDeps.exclude;
|
|
163
177
|
if (!exclude)
|
|
@@ -173,7 +187,8 @@ async function getPageDeps(config, pageConfigs) {
|
|
|
173
187
|
{
|
|
174
188
|
;
|
|
175
189
|
[true, false].forEach((isForClientSide) => {
|
|
176
|
-
|
|
190
|
+
;
|
|
191
|
+
[...pageConfigs, pageConfigGlobal].forEach((pageConfig) => {
|
|
177
192
|
Object.entries(pageConfig.configValueSources).forEach(([configName]) => {
|
|
178
193
|
const runtimeEnv = {
|
|
179
194
|
isForClientSide,
|
|
@@ -188,16 +203,7 @@ async function getPageDeps(config, pageConfigs) {
|
|
|
188
203
|
const { definedAt } = configValueSource;
|
|
189
204
|
if (definedAt.definedBy)
|
|
190
205
|
return;
|
|
191
|
-
|
|
192
|
-
addEntry(
|
|
193
|
-
// optimizeDeps.entries expects filesystem absolute paths
|
|
194
|
-
definedAt.filePathAbsoluteFilesystem, isForClientSide, definedAt);
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
addInclude(
|
|
198
|
-
// optimizeDeps.include expects npm packages
|
|
199
|
-
definedAt.importPathAbsolute, isForClientSide, definedAt);
|
|
200
|
-
}
|
|
206
|
+
addEntryOrInclude(definedAt, isForClientSide, definedAt);
|
|
201
207
|
});
|
|
202
208
|
});
|
|
203
209
|
});
|
|
@@ -214,13 +220,26 @@ async function getPageDeps(config, pageConfigs) {
|
|
|
214
220
|
});
|
|
215
221
|
}
|
|
216
222
|
// Add virtual files.
|
|
217
|
-
// -
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
223
|
+
// - Vite 8+ (Rolldown-based dep scanner) crawls virtual IDs natively — its scanner routes
|
|
224
|
+
// through `environment.pluginContainer.resolveId()`, so Vike's resolveId/load handlers
|
|
225
|
+
// run during the scan and the virtual file's transitive deps are seen.
|
|
226
|
+
// - Vite ≤7 (esbuild-based dep scanner) cannot crawl virtual IDs — those virtuals' deps
|
|
227
|
+
// surface lazily and trigger "✨ new dependencies optimized" reload cycles. As a
|
|
228
|
+
// workaround we could materialize each virtual to a real file under
|
|
229
|
+
// `node_modules/.vike/optimizeDeps-virtuals/`; an implementation lives in the reverted
|
|
230
|
+
// commit https://github.com/vikejs/vike/commit/b068009c3 (re-apply if Vite ≤7 support
|
|
231
|
+
// matters).
|
|
221
232
|
{
|
|
222
233
|
const { hasClientRouting, hasServerRouting, clientEntries } = analyzeClientEntries(pageConfigs, config);
|
|
223
|
-
Object.values(clientEntries).forEach((
|
|
234
|
+
Object.values(clientEntries).forEach(({ entryTarget, entryFilePath }) => {
|
|
235
|
+
if (entryFilePath) {
|
|
236
|
+
addEntryOrInclude(entryFilePath, true);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Page-entry virtual IDs have no file path.
|
|
240
|
+
addEntry(entryTarget, true);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
224
243
|
if (hasClientRouting)
|
|
225
244
|
addEntry(virtualFileIdGlobalEntryClientCR, true);
|
|
226
245
|
if (hasServerRouting)
|
|
@@ -258,3 +277,20 @@ function remove(input) {
|
|
|
258
277
|
list = list.filter((e) => !ALWAYS_REMOVE.includes(e));
|
|
259
278
|
return list;
|
|
260
279
|
}
|
|
280
|
+
// Sanity-check that the legacy `config.optimizeDeps` and `config.ssr.optimizeDeps` slots
|
|
281
|
+
// stay in sync with the corresponding environment values — so logging only the env values
|
|
282
|
+
// (above) isn't hiding anything.
|
|
283
|
+
function assertEnvsInSyncWithLegacy(config) {
|
|
284
|
+
const client = config.environments.client?.optimizeDeps;
|
|
285
|
+
assert(client);
|
|
286
|
+
assert(deepEqual(config.optimizeDeps.entries, client.entries));
|
|
287
|
+
assert(deepEqual(config.optimizeDeps.include, client.include));
|
|
288
|
+
assert(deepEqual(config.optimizeDeps.exclude, client.exclude));
|
|
289
|
+
const ssr = config.environments.ssr?.optimizeDeps;
|
|
290
|
+
assert(ssr);
|
|
291
|
+
/* Vite doesn't seem to support config.ssr.optimizeDeps.entries (vite@7.0.6, July 2025)
|
|
292
|
+
assert(deepEqual(config.ssr.optimizeDeps.entries, ssr.entries))
|
|
293
|
+
*/
|
|
294
|
+
assert(deepEqual(config.ssr.optimizeDeps.include, ssr.include));
|
|
295
|
+
assert(deepEqual(config.ssr.optimizeDeps.exclude, ssr.exclude));
|
|
296
|
+
}
|
|
@@ -2,8 +2,10 @@ export { pluginDev };
|
|
|
2
2
|
export { logDockerHint };
|
|
3
3
|
import { optimizeDeps, resolveOptimizeDeps } from './pluginDev/optimizeDeps.js';
|
|
4
4
|
import { determineFsAllowList } from './pluginDev/determineFsAllowList.js';
|
|
5
|
+
import { autoAddVikeSkill } from './pluginDev/autoAddVikeSkill.js';
|
|
5
6
|
import { addSsrMiddleware } from '../shared/addSsrMiddleware.js';
|
|
6
7
|
import { isDebugError } from '../../../utils/debug.js';
|
|
8
|
+
import { setTimeoutUnref } from '../../../utils/setTimeoutUnref.js';
|
|
7
9
|
import { applyDev } from '../../../utils/isDev.js';
|
|
8
10
|
import { isDocker } from '../../../utils/isDocker.js';
|
|
9
11
|
import { assertWarning } from '../../../utils/assert.js';
|
|
@@ -34,6 +36,21 @@ function pluginDev() {
|
|
|
34
36
|
logDockerHint(config.server.host);
|
|
35
37
|
},
|
|
36
38
|
},
|
|
39
|
+
configureServer: {
|
|
40
|
+
handler(server) {
|
|
41
|
+
// Apply late — after the dev server is up and running, and after the first page requests — so that it never slows down dev start.
|
|
42
|
+
const run = () => {
|
|
43
|
+
setTimeoutUnref(() => autoAddVikeSkill(config.root), 60 * 1000);
|
|
44
|
+
};
|
|
45
|
+
if (server.httpServer) {
|
|
46
|
+
server.httpServer.once('listening', run);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Middleware mode: the HTTP server is owned by the user.
|
|
50
|
+
run();
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
},
|
|
37
54
|
},
|
|
38
55
|
{
|
|
39
56
|
name: 'vike:pluginDev:post',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { pluginStripPointerImportAttribute };
|
|
2
|
+
import { getImportStatements } from '../shared/parseEsModule.js';
|
|
2
3
|
import { getMagicString } from '../shared/getMagicString.js';
|
|
3
4
|
import '../assertEnvVite.js';
|
|
4
5
|
// Match `with { type: 'vike:pointer' }` (with optional whitespace variations)
|
|
@@ -14,18 +15,38 @@ function pluginStripPointerImportAttribute() {
|
|
|
14
15
|
},
|
|
15
16
|
},
|
|
16
17
|
handler(code, id) {
|
|
17
|
-
|
|
18
|
-
if (!runtimeAttrRE.test(code))
|
|
19
|
-
return;
|
|
20
|
-
const { magicString, getMagicStringResult } = getMagicString(code, id);
|
|
21
|
-
runtimeAttrRE.lastIndex = 0;
|
|
22
|
-
let match;
|
|
23
|
-
while ((match = runtimeAttrRE.exec(code)) !== null) {
|
|
24
|
-
magicString.remove(match.index, match.index + match[0].length);
|
|
25
|
-
}
|
|
26
|
-
return getMagicStringResult();
|
|
18
|
+
return stripPointerImportAttributes(code, id);
|
|
27
19
|
},
|
|
28
20
|
},
|
|
29
21
|
},
|
|
30
22
|
];
|
|
31
23
|
}
|
|
24
|
+
async function stripPointerImportAttributes(code, id) {
|
|
25
|
+
// Fast path: skip parsing when there is nothing to strip
|
|
26
|
+
runtimeAttrRE.lastIndex = 0;
|
|
27
|
+
if (!runtimeAttrRE.test(code))
|
|
28
|
+
return;
|
|
29
|
+
// Restrict stripping to genuine `import` statements, so that we don't touch occurrences
|
|
30
|
+
// inside string literals/comments (e.g. documentation code examples).
|
|
31
|
+
// https://github.com/brillout/docpress/issues/167
|
|
32
|
+
let importStatements;
|
|
33
|
+
try {
|
|
34
|
+
importStatements = await getImportStatements(code);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Not parsable as an ES module (e.g. a raw Markdown file) => leave it untouched
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { magicString, getMagicStringResult } = getMagicString(code, id);
|
|
41
|
+
for (const { ss, se } of importStatements)
|
|
42
|
+
stripAttribute(magicString, code, ss, se);
|
|
43
|
+
return getMagicStringResult();
|
|
44
|
+
}
|
|
45
|
+
function stripAttribute(magicString, code, start, end) {
|
|
46
|
+
const region = code.slice(start, end);
|
|
47
|
+
runtimeAttrRE.lastIndex = 0;
|
|
48
|
+
let match;
|
|
49
|
+
while ((match = runtimeAttrRE.exec(region)) !== null) {
|
|
50
|
+
magicString.remove(start + match.index, start + match.index + match[0].length);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { generateVirtualFilePageEntry };
|
|
2
|
-
import { assert, getProjectError } from '../../../../utils/assert.js';
|
|
2
|
+
import { assert, getDebugInfoStr, getProjectError } from '../../../../utils/assert.js';
|
|
3
3
|
import { parseVirtualFileId, generateVirtualFileId } from '../../../../shared-server-node/virtualFileId.js';
|
|
4
4
|
import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
|
|
5
5
|
import { extractAssetsAddQuery } from '../../../../shared-server-node/extractAssetsQuery.js';
|
|
@@ -26,12 +26,10 @@ async function generateVirtualFilePageEntry(id, isDev) {
|
|
|
26
26
|
assert(pageConfig);
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
throw getProjectError('Outdated request');
|
|
34
|
-
//*/
|
|
29
|
+
if (!pageConfig) {
|
|
30
|
+
// Happens very seldom and can't reproduce reliably. Some kind of HMR race condition? It still happens as of June 2026 with Cloudflare Workers in development — but it isn't blocking, reloading the page fixes the issue.
|
|
31
|
+
throw getProjectError(`Outdated request. Try again. ${getDebugInfoStr({ id, pageId })}`);
|
|
32
|
+
}
|
|
35
33
|
}
|
|
36
34
|
const code = getCode(pageConfig, isForClientSide, pageId, resolveIncludeAssetsImportedByServer(vikeConfig.config), isDev);
|
|
37
35
|
debug(id, isForClientSide ? 'CLIENT-SIDE' : 'SERVER-SIDE', code);
|
|
@@ -3,7 +3,7 @@ export { getConfigValueSourceRelevantAnyEnv };
|
|
|
3
3
|
export { isRuntimeEnvMatch };
|
|
4
4
|
export { isConfigSourceValueNull };
|
|
5
5
|
export type { RuntimeEnv };
|
|
6
|
-
import type {
|
|
6
|
+
import type { ConfigEnv, ConfigValueSource, PageConfigBuildTime, PageConfigGlobalBuildTime } from '../../../../types/PageConfig.js';
|
|
7
7
|
import '../../assertEnvVite.js';
|
|
8
8
|
type RuntimeEnv = {
|
|
9
9
|
isForClientSide: boolean;
|
|
@@ -15,5 +15,5 @@ type RuntimeEnv = {
|
|
|
15
15
|
type PageConfigPartial = Pick<PageConfigBuildTime | PageConfigGlobalBuildTime, 'configValueSources' | 'configDefinitions'>;
|
|
16
16
|
declare function getConfigValueSourcesRelevant(configName: string, runtimeEnv: RuntimeEnv, pageConfig: PageConfigPartial): ConfigValueSource[];
|
|
17
17
|
declare function getConfigValueSourceRelevantAnyEnv(configName: string, pageConfig: PageConfigPartial): null | ConfigValueSource;
|
|
18
|
-
declare function isRuntimeEnvMatch(configEnv:
|
|
18
|
+
declare function isRuntimeEnvMatch(configEnv: ConfigEnv, runtimeEnv: RuntimeEnv): boolean;
|
|
19
19
|
declare function isConfigSourceValueNull(source: ConfigValueSource): boolean | null;
|
|
@@ -13,7 +13,7 @@ import pc from '@brillout/picocolors';
|
|
|
13
13
|
import { logConfigInfo } from '../shared/loggerDev.js';
|
|
14
14
|
import { getFilePathToShowToUserModule } from '../shared/getFilePath.js';
|
|
15
15
|
import { updateUserFiles } from '../../../server/runtime/globalContext.js';
|
|
16
|
-
import { isPlusFile } from '../shared/resolveVikeConfigInternal/
|
|
16
|
+
import { isPlusFile } from '../shared/resolveVikeConfigInternal/crawlPlusFiles.js';
|
|
17
17
|
import { isTemporaryBuildFile } from '../shared/resolveVikeConfigInternal/transpileAndExecuteFile.js';
|
|
18
18
|
import { debugFileChange, getVikeConfigError } from '../../../shared-server-node/getVikeConfigError.js';
|
|
19
19
|
import '../assertEnvVite.js';
|
|
@@ -14,7 +14,7 @@ function addSsrMiddleware(middlewares, config, isPreview, isPrerenderingEnabled)
|
|
|
14
14
|
const pageContextInit = {
|
|
15
15
|
urlOriginal: url,
|
|
16
16
|
headersOriginal: headers,
|
|
17
|
-
|
|
17
|
+
_nodeDev: { req, res },
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(pageContextInit, 'userAgent', {
|
|
20
20
|
get() {
|
|
@@ -9,6 +9,9 @@ function getMagicString(code, id) {
|
|
|
9
9
|
return undefined;
|
|
10
10
|
return {
|
|
11
11
|
code: magicString.toString(),
|
|
12
|
+
// magic-string@1's SourceMap.sourcesContent is typed as (string | null)[], whereas Rollup's
|
|
13
|
+
// ExistingRawSourceMap expects string[]. We never pass `includeContent`, so sourcesContent is
|
|
14
|
+
// always undefined at runtime and this cast is safe.
|
|
12
15
|
map: magicString.generateMap({ hires: true, source: id }),
|
|
13
16
|
};
|
|
14
17
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { isVite8OrAbove };
|
|
2
|
+
import { assert } from '../../../utils/assert.js';
|
|
3
|
+
import { isVersionMatch } from '../../../utils/assertVersion.js';
|
|
4
|
+
import '../assertEnvVite.js';
|
|
5
|
+
function isVite8OrAbove(config) {
|
|
6
|
+
const viteVersion = config._viteVersionResolved;
|
|
7
|
+
assert(viteVersion);
|
|
8
|
+
return isVersionMatch(viteVersion, ['8.0.0']);
|
|
9
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { isViteCli };
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { getViteCliArgs };
|
|
3
|
+
export { getViteBuildCliArgs };
|
|
4
|
+
export { getViteCliCommand };
|
|
4
5
|
import '../assertEnvVite.js';
|
|
5
6
|
declare function isViteCli(): boolean;
|
|
6
7
|
type ConfigFromCli = {
|
|
@@ -10,5 +11,9 @@ type ConfigFromCli = {
|
|
|
10
11
|
build: Record<string, unknown>;
|
|
11
12
|
};
|
|
12
13
|
type ViteCommand = 'dev' | 'build' | 'optimize' | 'preview';
|
|
13
|
-
declare function
|
|
14
|
-
declare function
|
|
14
|
+
declare function getViteCliCommand(): ViteCommand | null;
|
|
15
|
+
declare function getViteBuildCliArgs(): null | ConfigFromCli;
|
|
16
|
+
declare function getViteCliArgs(): null | {
|
|
17
|
+
root: string | undefined;
|
|
18
|
+
configFile: string | undefined;
|
|
19
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { isViteCli };
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { getViteCliArgs };
|
|
3
|
+
export { getViteBuildCliArgs };
|
|
4
|
+
export { getViteCliCommand };
|
|
4
5
|
import { assert } from '../../../utils/assert.js';
|
|
5
6
|
import { isObject } from '../../../utils/isObject.js';
|
|
6
7
|
import { isToolCli } from '../../../utils/isToolCli.js';
|
|
@@ -10,7 +11,7 @@ const desc = 'vike:vite-cli-simulation';
|
|
|
10
11
|
function isViteCli() {
|
|
11
12
|
return isToolCli('vite');
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
+
function getViteCliCommand() {
|
|
14
15
|
if (!isViteCli())
|
|
15
16
|
return null;
|
|
16
17
|
let command;
|
|
@@ -45,7 +46,7 @@ function getViteCommandFromCli() {
|
|
|
45
46
|
assert(command);
|
|
46
47
|
return command;
|
|
47
48
|
}
|
|
48
|
-
function
|
|
49
|
+
function getViteBuildCliArgs() {
|
|
49
50
|
if (!isViteCli())
|
|
50
51
|
return null;
|
|
51
52
|
// Copied & adapted from Vite
|
|
@@ -135,3 +136,22 @@ function getViteConfigForBuildFromCli() {
|
|
|
135
136
|
return ret;
|
|
136
137
|
}
|
|
137
138
|
}
|
|
139
|
+
function getViteCliArgs() {
|
|
140
|
+
if (!isViteCli())
|
|
141
|
+
return null;
|
|
142
|
+
const cli = cac(desc);
|
|
143
|
+
cli.option('-c, --config <file>', desc);
|
|
144
|
+
let result = null;
|
|
145
|
+
const setResult = (root, options) => {
|
|
146
|
+
assert(root === undefined || typeof root === 'string');
|
|
147
|
+
assert(isObject(options));
|
|
148
|
+
assert(options.config === undefined || typeof options.config === 'string');
|
|
149
|
+
result = { root, configFile: options.config };
|
|
150
|
+
};
|
|
151
|
+
cli.command('[root]', desc).alias('serve').alias('dev').action(setResult);
|
|
152
|
+
cli.command('build [root]', desc).action(setResult);
|
|
153
|
+
cli.command('optimize [root]', desc).action(setResult);
|
|
154
|
+
cli.command('preview [root]', desc).action(setResult);
|
|
155
|
+
cli.parse();
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
@@ -29,7 +29,6 @@ import { getBetterError } from '../../../utils/getBetterError.js';
|
|
|
29
29
|
import { getRequestId_withAsyncHook } from '../../../server/runtime/asyncHook.js';
|
|
30
30
|
import { getRequestTag } from '../../../server/runtime/renderPageServer.js';
|
|
31
31
|
import '../assertEnvVite.js';
|
|
32
|
-
import { isDeno } from '../../../utils/isDeno.js';
|
|
33
32
|
assertIsNotProductionRuntime();
|
|
34
33
|
setLogRuntimeDev(logErrorServerDev, logRuntimeInfoDev);
|
|
35
34
|
setAssertOnBeforeErr((err) => {
|
|
@@ -139,14 +138,16 @@ function logDev(msg, logType, tagSource, tagTool, doNotAddTags) {
|
|
|
139
138
|
}
|
|
140
139
|
function getTagSource(requestId = null) {
|
|
141
140
|
const requestIdFromStore = getRequestId_withAsyncHook();
|
|
142
|
-
if (requestIdFromStore !== null
|
|
143
|
-
// Workaround for Deno bug: https://github.com/vikejs/vike/issues/3240
|
|
144
|
-
!isDeno()) {
|
|
141
|
+
if (requestIdFromStore !== null) {
|
|
145
142
|
if (requestId === null) {
|
|
146
143
|
requestId = requestIdFromStore;
|
|
147
144
|
}
|
|
148
145
|
else {
|
|
149
|
-
assert
|
|
146
|
+
/* Surprisingly, this assert can fail:
|
|
147
|
+
* - https://github.com/vikejs/vike/issues/3240
|
|
148
|
+
* - https://github.com/vikejs/vike/issues/3289
|
|
149
|
+
assert(requestId === requestIdFromStore)
|
|
150
|
+
*/
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
if (requestId === null)
|