poveste 0.8.0 → 0.8.1
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/dist/node/build.js +17 -4
- package/dist/node/collect/define-globals.d.ts +1 -0
- package/dist/node/collect/define-globals.js +42 -0
- package/dist/node/collect/index.js +4 -0
- package/dist/node/collect/worker.d.ts +1 -0
- package/dist/node/collect/worker.js +5 -0
- package/dist/node/optimize-entries.d.ts +3 -0
- package/dist/node/optimize-entries.js +48 -0
- package/dist/node/vite.js +4 -0
- package/package.json +5 -5
package/dist/node/build.js
CHANGED
|
@@ -85,10 +85,14 @@ export async function build(ctx) {
|
|
|
85
85
|
build: {
|
|
86
86
|
lib: false,
|
|
87
87
|
rollupOptions: {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
]
|
|
88
|
+
// Named, not an array. With an array the bundler derives `[name]` from the
|
|
89
|
+
// path, and `APP_PATH` is absolute — so any framework whose `entryFileNames`
|
|
90
|
+
// refuses a path-shaped `[name]` fails the build outright (#369, and
|
|
91
|
+
// histoire-dev/histoire#802 before it). The keys make `[name]` the key.
|
|
92
|
+
input: {
|
|
93
|
+
'bundle-main': join(APP_PATH, 'bundle-main.js'),
|
|
94
|
+
'bundle-sandbox': join(APP_PATH, 'bundle-sandbox.js'),
|
|
95
|
+
},
|
|
92
96
|
plugins: [
|
|
93
97
|
{
|
|
94
98
|
name: 'poveste-build-rollup-options-override',
|
|
@@ -164,6 +168,15 @@ export async function build(ctx) {
|
|
|
164
168
|
}
|
|
165
169
|
},
|
|
166
170
|
};
|
|
171
|
+
// A framework that declares Vite environments gives each one its own
|
|
172
|
+
// `build.outDir`, and that wins over the top-level value for the environment's
|
|
173
|
+
// output — so the book was written to the framework's directory (Vike: `dist/client`)
|
|
174
|
+
// while poveste kept looking in `outDir` (#369). Only the client environment
|
|
175
|
+
// builds the book. Where no framework declared environments there is nothing to
|
|
176
|
+
// override, and where one did this puts the book back where poveste reads it.
|
|
177
|
+
if (config.environments?.client?.build) {
|
|
178
|
+
config.environments.client.build.outDir = ctx.config.outDir;
|
|
179
|
+
}
|
|
167
180
|
// Force vite build options
|
|
168
181
|
Object.assign(config.build, {
|
|
169
182
|
outDir: ctx.config.outDir,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function globalsFromDefine(define: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Story collection runs in a Node worker. Externalised dependencies are loaded by
|
|
2
|
+
// native Node ESM, so Vite never applies `define` to them — and a bare compile-time
|
|
3
|
+
// feature flag is just an undefined identifier there. vue-i18n reading
|
|
4
|
+
// `__VUE_PROD_DEVTOOLS__` was the reported case (#284); anything with build-time
|
|
5
|
+
// flags fails the same way.
|
|
6
|
+
//
|
|
7
|
+
// The fix is to give the collection environment the same values a real build would
|
|
8
|
+
// substitute, taken from Vite's own resolved `define` rather than a list of library
|
|
9
|
+
// names this package would have to keep current.
|
|
10
|
+
// Only `__FLAG__`-shaped keys are seeded. Every flag this exists for follows that
|
|
11
|
+
// convention — `__VUE_OPTIONS_API__`, `__VUE_PROD_DEVTOOLS__`, `__VUE_I18N_LEGACY_API__`,
|
|
12
|
+
// `__INTLIFY_PROD_DEVTOOLS__` — and narrow is the right failure here. A browser-targeted
|
|
13
|
+
// config shimming a Node global (`define: { process: '{"env":{}}' }` is a real shape)
|
|
14
|
+
// would otherwise replace the collection worker's own `process`, surfacing far from the
|
|
15
|
+
// config that caused it. Refusing to evaluate arbitrary expressions while letting
|
|
16
|
+
// arbitrary identifiers overwrite the runtime would be a guard in name only.
|
|
17
|
+
// `process.env.NODE_ENV` and friends fail the same test, being member expressions.
|
|
18
|
+
const FEATURE_FLAG = /^__[A-Z0-9_]+__$/;
|
|
19
|
+
// Vite `define` values are JS expression *source*. A plugin-injected flag arrives
|
|
20
|
+
// already parsed (`false`), while a user's `define: { X: 'false' }` arrives as the
|
|
21
|
+
// string `"false"` — and seeding that string would make the flag *truthy*, silently
|
|
22
|
+
// inverting it. So strings are parsed as literals, and anything that is not a literal
|
|
23
|
+
// is skipped: evaluating arbitrary expressions here is not something this should do.
|
|
24
|
+
export function globalsFromDefine(define) {
|
|
25
|
+
const globals = {};
|
|
26
|
+
for (const [key, value] of Object.entries(define ?? {})) {
|
|
27
|
+
if (!FEATURE_FLAG.test(key)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (typeof value !== 'string') {
|
|
31
|
+
globals[key] = value;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
globals[key] = JSON.parse(value);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Not a literal — leave it undefined rather than guess at it.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return globals;
|
|
42
|
+
}
|
|
@@ -8,6 +8,7 @@ import { ViteNodeServer } from 'vite-node/server';
|
|
|
8
8
|
import { TEMP_PATH } from '../alias.js';
|
|
9
9
|
import { createPath } from '../tree.js';
|
|
10
10
|
import { slash } from '../util/fs.js';
|
|
11
|
+
import { globalsFromDefine } from './define-globals.js';
|
|
11
12
|
export function useCollectStories(options, ctx) {
|
|
12
13
|
const { server, mainServer } = options;
|
|
13
14
|
const node = new ViteNodeServer(server, {
|
|
@@ -34,6 +35,8 @@ export function useCollectStories(options, ctx) {
|
|
|
34
35
|
},
|
|
35
36
|
transformMode: ctx.config.viteNodeTransformMode,
|
|
36
37
|
});
|
|
38
|
+
// Same values a real build substitutes, so externalised deps see their flags.
|
|
39
|
+
const defineGlobals = globalsFromDefine(server.config.define);
|
|
37
40
|
const maxThreads = ctx.config.collectMaxThreads ?? cpus().length;
|
|
38
41
|
const threadsCount = ctx.mode === 'dev'
|
|
39
42
|
? Math.max(Math.min(maxThreads, Math.floor(cpus().length / 2)), 1)
|
|
@@ -83,6 +86,7 @@ export function useCollectStories(options, ctx) {
|
|
|
83
86
|
base: server.config.base,
|
|
84
87
|
storyFile,
|
|
85
88
|
port: workerPort,
|
|
89
|
+
defineGlobals,
|
|
86
90
|
};
|
|
87
91
|
const { storyData } = await threadPool.run(payload, {
|
|
88
92
|
transferList: [
|
|
@@ -22,6 +22,11 @@ parentPort.on('message', (message) => {
|
|
|
22
22
|
export default async (payload) => {
|
|
23
23
|
const startTime = performance.now();
|
|
24
24
|
process.env.HST_COLLECT = 'true';
|
|
25
|
+
// Before any module runs: an externalised dep reads these at import time.
|
|
26
|
+
for (const [key, value] of Object.entries(payload.defineGlobals ?? {})) {
|
|
27
|
+
;
|
|
28
|
+
globalThis[key] = value;
|
|
29
|
+
}
|
|
25
30
|
_rpc = createBirpc({}, {
|
|
26
31
|
post: data => payload.port.postMessage(data),
|
|
27
32
|
on: data => payload.port.on('message', data),
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PovesteConfig } from '@poveste/shared';
|
|
2
|
+
export declare function optimizeEntries(config: Pick<PovesteConfig, 'storyMatch' | 'storyIgnored' | 'setupFile'>, root: string, isServer: boolean): string[];
|
|
3
|
+
export declare function setupFileEntry(setupFile: PovesteConfig['setupFile'], isServer: boolean): string | undefined;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { globbySync } from 'globby';
|
|
2
|
+
import { resolve } from 'pathe';
|
|
3
|
+
// Vite pre-bundles whatever its dependency scanner reaches by crawling
|
|
4
|
+
// `optimizeDeps.entries`. Two things in a book route around that scan:
|
|
5
|
+
//
|
|
6
|
+
// - stories are loaded dynamically, never statically imported from the app entry
|
|
7
|
+
// - the setup file is reached through `virtual:$poveste-setup`, an id the scanner
|
|
8
|
+
// cannot resolve
|
|
9
|
+
//
|
|
10
|
+
// So a dependency used only in a story or a setup file is discovered on first
|
|
11
|
+
// navigation instead, and Vite answers with `optimized dependencies changed.
|
|
12
|
+
// reloading` — a full reload that drops the preview's scroll and state (#282).
|
|
13
|
+
//
|
|
14
|
+
// The stories are resolved here rather than handed over as patterns, because
|
|
15
|
+
// `storyIgnored` cannot be expressed as entry patterns. Vite globs the whole entries
|
|
16
|
+
// array together, so a `!**/dist/**` negation would also match `APP_PATH`, which *is*
|
|
17
|
+
// `<poveste-app>/dist` — silently dropping the app's own scan entries. Resolving the
|
|
18
|
+
// files gives `storyIgnored` its exact meaning and cannot touch anything else.
|
|
19
|
+
export function optimizeEntries(config, root, isServer) {
|
|
20
|
+
// Same call the collector makes, so the scanner sees exactly the story set the
|
|
21
|
+
// book will load — no stale `dist/` copies the book itself excludes.
|
|
22
|
+
const stories = globbySync(config.storyMatch, {
|
|
23
|
+
cwd: root,
|
|
24
|
+
ignore: config.storyIgnored,
|
|
25
|
+
absolute: true,
|
|
26
|
+
});
|
|
27
|
+
const setup = setupFileEntry(config.setupFile, isServer);
|
|
28
|
+
return setup ? [...stories, resolve(root, setup)] : stories;
|
|
29
|
+
}
|
|
30
|
+
// Mirrors how `virtual/vite-plugin.ts` picks the file. These are documented
|
|
31
|
+
// root-relative and written with a leading slash (`/src/setup.ts`), which
|
|
32
|
+
// `resolve` would read as absolute.
|
|
33
|
+
export function setupFileEntry(setupFile, isServer) {
|
|
34
|
+
if (!setupFile) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
let file;
|
|
38
|
+
if (typeof setupFile === 'string') {
|
|
39
|
+
file = setupFile;
|
|
40
|
+
}
|
|
41
|
+
else if (isServer && 'server' in setupFile) {
|
|
42
|
+
file = setupFile.server;
|
|
43
|
+
}
|
|
44
|
+
else if (!isServer && 'browser' in setupFile) {
|
|
45
|
+
file = setupFile.browser;
|
|
46
|
+
}
|
|
47
|
+
return file ? file.replace(/^\/+/, '') : undefined;
|
|
48
|
+
}
|
package/dist/node/vite.js
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join, relative } from 'pathe';
|
|
|
5
5
|
import { loadConfigFromFile as loadViteConfigFromFile, mergeConfig as mergeViteConfig, searchForWorkspaceRoot, } from 'vite';
|
|
6
6
|
import { APP_PATH, TEMP_PATH } from './alias.js';
|
|
7
7
|
import { createMarkdownPlugins } from './markdown.js';
|
|
8
|
+
import { optimizeEntries } from './optimize-entries.js';
|
|
8
9
|
import { notifyStoryChange } from './stories.js';
|
|
9
10
|
import { chromeCssScopePlugin, globalStylesPlugin, userCssScopePlugin, } from './style-isolation/index.js';
|
|
10
11
|
import { applyHeadTransform } from './util/head.js';
|
|
@@ -124,6 +125,9 @@ export async function getViteConfigWithPlugins(isServer, ctx) {
|
|
|
124
125
|
entries: [
|
|
125
126
|
`${APP_PATH}/bundle-main.js`,
|
|
126
127
|
`${APP_PATH}/bundle-sandbox.js`,
|
|
128
|
+
// Without these the scanner never sees a story or the setup file, and
|
|
129
|
+
// their deps cost a full reload when they turn up later (#282).
|
|
130
|
+
...optimizeEntries(ctx.config, ctx.root, isServer),
|
|
127
131
|
],
|
|
128
132
|
include: optimizeDeps([
|
|
129
133
|
'shiki',
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poveste",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.1",
|
|
5
5
|
"description": "Interactive component playgrounds for Vue, Svelte and Nuxt — a maintained, drop-in successor to histoire",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan"
|
|
@@ -98,10 +98,10 @@
|
|
|
98
98
|
"sirv": "^3.0.0",
|
|
99
99
|
"unhead": "^3.1.0",
|
|
100
100
|
"vite-node": "^6.0.0",
|
|
101
|
-
"@poveste/
|
|
102
|
-
"@poveste/
|
|
103
|
-
"@poveste/shared": "^0.8.
|
|
104
|
-
"@poveste/vendors": "^0.8.
|
|
101
|
+
"@poveste/app": "^0.8.1",
|
|
102
|
+
"@poveste/controls": "^0.8.1",
|
|
103
|
+
"@poveste/shared": "^0.8.1",
|
|
104
|
+
"@poveste/vendors": "^0.8.1"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
107
|
"@types/fs-extra": "^11.0.4",
|