poveste 0.2.0 → 0.3.0

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 (35) hide show
  1. package/dist/node/build.js +0 -3
  2. package/dist/node/builtin-plugins/tailwind-tokens.d.ts +6 -1
  3. package/dist/node/builtin-plugins/tailwind-tokens.d.ts.map +1 -1
  4. package/dist/node/builtin-plugins/tailwind-tokens.js +169 -33
  5. package/dist/node/builtin-plugins/vanilla-support/MountStory.d.ts +3 -3
  6. package/dist/node/builtin-plugins/vanilla-support/RenderStory.d.ts +5 -5
  7. package/dist/node/collect/index.d.ts.map +1 -1
  8. package/dist/node/collect/index.js +1 -3
  9. package/dist/node/config.d.ts +2 -18
  10. package/dist/node/config.d.ts.map +1 -1
  11. package/dist/node/config.js +3 -0
  12. package/dist/node/dom/env.d.ts.map +1 -1
  13. package/dist/node/dom/env.js +10 -6
  14. package/dist/node/index.d.ts +0 -7
  15. package/dist/node/index.d.ts.map +1 -1
  16. package/dist/node/markdown.d.ts.map +1 -1
  17. package/dist/node/markdown.js +21 -3
  18. package/dist/node/stories.js +1 -1
  19. package/dist/node/style-isolation/entry-css-merger.d.ts.map +1 -1
  20. package/dist/node/style-isolation/entry-css-merger.js +8 -7
  21. package/dist/node/vite.js +1 -1
  22. package/package.json +10 -12
  23. package/src/node/__tests__/dom-env.spec.ts +19 -1
  24. package/src/node/build.ts +2 -6
  25. package/src/node/builtin-plugins/tailwind-tokens.ts +190 -34
  26. package/src/node/collect/index.ts +1 -3
  27. package/src/node/config.ts +3 -0
  28. package/src/node/dom/env.ts +10 -6
  29. package/src/node/index.ts +0 -8
  30. package/src/node/markdown.ts +25 -3
  31. package/src/node/stories.ts +1 -1
  32. package/src/node/style-isolation/__tests__/entry-css-merger.spec.ts +37 -18
  33. package/src/node/style-isolation/entry-css-merger.ts +10 -9
  34. package/src/node/vite.ts +4 -4
  35. package/tsconfig.json +1 -1
@@ -1,4 +1,4 @@
1
- import type { OutputBundle } from 'rollup'
1
+ import type { Rolldown } from 'vite'
2
2
  import { describe, expect, it } from 'vitest'
3
3
  import { entryCssMergerPlugin } from '../entry-css-merger.js'
4
4
  import { USER_CSS_MARK_END, USER_CSS_MARK_START } from '../vite-plugin.js'
@@ -30,25 +30,44 @@ function mark(css: string): string {
30
30
  return `${USER_CSS_MARK_START}\n${css}\n${USER_CSS_MARK_END}\n`
31
31
  }
32
32
 
33
+ // Rolldown ignores assignment to `bundle` in generateBundle, so merged CSS is
34
+ // added via this.emitFile. Capture those emits to assert on them.
35
+ function runMerger(plugin: any, bundle: Rolldown.OutputBundle) {
36
+ const emitted = new Map<string, any>()
37
+ const ctx = {
38
+ emitFile: (file: any) => {
39
+ emitted.set(file.fileName, file)
40
+ return file.fileName
41
+ },
42
+ }
43
+ ;(plugin.generateBundle as any).call(ctx, {}, bundle)
44
+ return emitted
45
+ }
46
+
33
47
  describe('entry-css-merger', () => {
34
48
  it('produces one CSS asset per entry chunk', async () => {
35
49
  const plugin = entryCssMergerPlugin()
36
- const bundle: OutputBundle = {
50
+ const bundle: Rolldown.OutputBundle = {
37
51
  'bundle-main.js': fakeChunk('bundle-main', ['route1.css', 'route2.css']),
38
52
  'bundle-sandbox.js': fakeChunk('bundle-sandbox', ['sandbox-route.css']),
39
53
  'route1.css': fakeAsset('route1.css', 'a {}'),
40
54
  'route2.css': fakeAsset('route2.css', 'b {}'),
41
55
  'sandbox-route.css': fakeAsset('sandbox-route.css', 'c {}'),
42
56
  }
43
- await (plugin.generateBundle as any).call({ emitFile: () => '' }, {}, bundle)
57
+ const emitted = runMerger(plugin, bundle)
44
58
 
45
- const cssAssets = Object.values(bundle).filter(a => a.type === 'asset' && a.fileName.endsWith('.css'))
59
+ const cssAssets = [...emitted.values()].filter(a => a.fileName.endsWith('.css'))
46
60
  expect(cssAssets).toHaveLength(2)
47
- const mainCss = cssAssets.find(a => a.fileName === 'bundle-main.css')
48
- const sandboxCss = cssAssets.find(a => a.fileName === 'bundle-sandbox.css')
61
+ const mainCss = emitted.get('bundle-main.css')
62
+ const sandboxCss = emitted.get('bundle-sandbox.css')
49
63
  expect(mainCss?.source).toContain('a {}')
50
64
  expect(mainCss?.source).toContain('b {}')
51
65
  expect(sandboxCss?.source).toContain('c {}')
66
+
67
+ // The per-chunk CSS assets are dropped from the bundle once merged.
68
+ expect(bundle['route1.css']).toBeUndefined()
69
+ expect(bundle['route2.css']).toBeUndefined()
70
+ expect(bundle['sandbox-route.css']).toBeUndefined()
52
71
  })
53
72
 
54
73
  it('wraps marked user CSS in @scope on the main entry when isolation is enabled', async () => {
@@ -57,14 +76,14 @@ describe('entry-css-merger', () => {
57
76
  scopeRoot: '.__poveste-render-story',
58
77
  mainEntryName: 'bundle-main',
59
78
  })
60
- const bundle: OutputBundle = {
79
+ const bundle: Rolldown.OutputBundle = {
61
80
  'bundle-main.js': fakeChunk('bundle-main', ['user.css', 'chrome.css']),
62
81
  'user.css': fakeAsset('user.css', mark('body { color: red }')),
63
82
  'chrome.css': fakeAsset('chrome.css', '@scope (.poveste-app-root) { .x {} }'),
64
83
  }
65
- await (plugin.generateBundle as any).call({ emitFile: () => '' }, {}, bundle)
84
+ const emitted = runMerger(plugin, bundle)
66
85
 
67
- const main = Object.values(bundle).find(a => a.type === 'asset' && a.fileName === 'bundle-main.css') as any
86
+ const main = emitted.get('bundle-main.css')
68
87
  expect(main.source).toContain('@scope (.__poveste-render-story)')
69
88
  expect(main.source).toContain('color: red')
70
89
  expect(main.source).toContain('@scope (.poveste-app-root)')
@@ -77,13 +96,13 @@ describe('entry-css-merger', () => {
77
96
  scopeRoot: '.__poveste-render-story',
78
97
  mainEntryName: 'bundle-main',
79
98
  })
80
- const bundle: OutputBundle = {
99
+ const bundle: Rolldown.OutputBundle = {
81
100
  'bundle-sandbox.js': fakeChunk('bundle-sandbox', ['user.css']),
82
101
  'user.css': fakeAsset('user.css', mark('body { color: red }')),
83
102
  }
84
- await (plugin.generateBundle as any).call({ emitFile: () => '' }, {}, bundle)
103
+ const emitted = runMerger(plugin, bundle)
85
104
 
86
- const sandbox = Object.values(bundle).find(a => a.type === 'asset' && a.fileName === 'bundle-sandbox.css') as any
105
+ const sandbox = emitted.get('bundle-sandbox.css')
87
106
  expect(sandbox.source).toContain('body')
88
107
  expect(sandbox.source).toContain('color: red')
89
108
  expect(sandbox.source).not.toContain('@scope')
@@ -95,14 +114,14 @@ describe('entry-css-merger', () => {
95
114
  const main = fakeChunk('bundle-main', ['app.css'], '', { imports: ['vendor.js'], isEntry: true })
96
115
  main.fileName = 'bundle-main.js'
97
116
  const vendor = { ...fakeChunk('vendor', ['vendor.css']), isEntry: false, fileName: 'vendor.js' }
98
- const bundle: OutputBundle = {
117
+ const bundle: Rolldown.OutputBundle = {
99
118
  'bundle-main.js': main,
100
119
  'vendor.js': vendor,
101
120
  'app.css': fakeAsset('app.css', '.app {}'),
102
121
  'vendor.css': fakeAsset('vendor.css', '.vendor {}'),
103
122
  }
104
- await (plugin.generateBundle as any).call({ emitFile: () => '' }, {}, bundle)
105
- const mainCss = Object.values(bundle).find(a => a.type === 'asset' && a.fileName === 'bundle-main.css') as any
123
+ const emitted = runMerger(plugin, bundle)
124
+ const mainCss = emitted.get('bundle-main.css')
106
125
  expect(mainCss.source).toContain('.app')
107
126
  expect(mainCss.source).toContain('.vendor')
108
127
  })
@@ -113,13 +132,13 @@ describe('entry-css-merger', () => {
113
132
  scopeRoot: '.__poveste-render-story',
114
133
  mainEntryName: 'bundle-main',
115
134
  })
116
- const bundle: OutputBundle = {
135
+ const bundle: Rolldown.OutputBundle = {
117
136
  'bundle-main.js': fakeChunk('bundle-main', ['user.css']),
118
137
  'user.css': fakeAsset('user.css', mark('body { color: red }')),
119
138
  }
120
- await (plugin.generateBundle as any).call({ emitFile: () => '' }, {}, bundle)
139
+ const emitted = runMerger(plugin, bundle)
121
140
 
122
- const main = Object.values(bundle).find(a => a.type === 'asset' && a.fileName === 'bundle-main.css') as any
141
+ const main = emitted.get('bundle-main.css')
123
142
  expect(main.source).not.toContain('@scope')
124
143
  expect(main.source).not.toContain(USER_CSS_MARK_START)
125
144
  })
@@ -1,4 +1,3 @@
1
- import type { OutputBundle } from 'rollup'
2
1
  import type { Plugin as VitePlugin } from 'vite'
3
2
  import { STORY_SCOPE_ROOT } from './selectors.js'
4
3
  import { wrapUserCss } from './transforms.js'
@@ -17,7 +16,7 @@ export function entryCssMergerPlugin(opts: EntryCssMergerOptions = { isolateStyl
17
16
  name: 'poveste:style-isolation:entry-css-merger',
18
17
  apply: 'build',
19
18
  enforce: 'post',
20
- generateBundle(_options, bundle: OutputBundle) {
19
+ generateBundle(_options, bundle) {
21
20
  function collectChunkCss(entryFileName: string, entryName: string, acc: Map<string, string[]>) {
22
21
  const seen = new Set<string>()
23
22
  const queue = [entryFileName]
@@ -48,6 +47,7 @@ export function entryCssMergerPlugin(opts: EntryCssMergerOptions = { isolateStyl
48
47
  }
49
48
 
50
49
  const mergedByEntry = new Map<string, string[]>()
50
+ const mergedCssAssets: string[] = []
51
51
  for (const [cssName, entries] of cssAssetUsedBy) {
52
52
  const asset = bundle[cssName]
53
53
  if (!asset || asset.type !== 'asset') continue
@@ -59,6 +59,13 @@ export function entryCssMergerPlugin(opts: EntryCssMergerOptions = { isolateStyl
59
59
  list.push(source)
60
60
  mergedByEntry.set(entryName, list)
61
61
  }
62
+ mergedCssAssets.push(cssName)
63
+ }
64
+
65
+ // Rolldown ignores assignment to `bundle` in generateBundle, so the merged
66
+ // files are added with this.emitFile. The now-merged per-chunk CSS assets
67
+ // are dropped so they don't ship as unscoped, orphaned duplicates.
68
+ for (const cssName of mergedCssAssets) {
62
69
  delete bundle[cssName]
63
70
  }
64
71
 
@@ -68,13 +75,7 @@ export function entryCssMergerPlugin(opts: EntryCssMergerOptions = { isolateStyl
68
75
  const finalSource = entryName === mainEntryName && opts.isolateStyles
69
76
  ? wrapMarkedUserCss(merged, scopeRoot)
70
77
  : stripMarkers(merged)
71
- bundle[fileName] = {
72
- type: 'asset',
73
- fileName,
74
- name: fileName,
75
- source: finalSource,
76
- needsCodeReference: false,
77
- } as any
78
+ this.emitFile({ type: 'asset', fileName, source: finalSource })
78
79
  }
79
80
 
80
81
  // Re-point CSS metadata: entries claim their own merged file; non-entry
package/src/node/vite.ts CHANGED
@@ -30,9 +30,9 @@ export async function mergePovesteViteConfig(viteConfig: InlineConfig, ctx: Cont
30
30
  const command = ctx.mode === 'dev' ? 'serve' : 'build'
31
31
  const overrides = typeof ctx.config.vite === 'function'
32
32
  ? await ctx.config.vite(viteConfig as ViteConfig, {
33
- mode: ctx.mode,
34
- command,
35
- })
33
+ mode: ctx.mode,
34
+ command,
35
+ })
36
36
  : ctx.config.vite
37
37
  if (overrides) {
38
38
  viteConfig = mergeViteConfig(viteConfig, overrides)
@@ -324,7 +324,7 @@ export async function getViteConfigWithPlugins(isServer: boolean, ctx: Context):
324
324
  name: 'poveste:flags',
325
325
  enforce: 'pre',
326
326
  transform(code, id) {
327
- if (id.match(/\.(vue|js)($|\?)/)) {
327
+ if (/\.(?:vue|js)(?:$|\?)/.test(id)) {
328
328
  const original = code
329
329
  for (const flag in flags) {
330
330
  code = code.replace(new RegExp(flag, 'g'), flags[flag])
package/tsconfig.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "baseUrl": ".",
11
11
  "rootDir": "src",
12
12
  "module": "ESNext",
13
- "moduleResolution": "node",
13
+ "moduleResolution": "bundler",
14
14
  "resolveJsonModule": true,
15
15
  "types": [
16
16
  "node"