poveste 0.1.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 (251) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +11 -0
  3. package/bin.mjs +4 -0
  4. package/client.d.ts +19 -0
  5. package/client.js +15 -0
  6. package/dist/controls.d.ts +2 -0
  7. package/dist/controls.d.ts.map +1 -0
  8. package/dist/controls.js +1 -0
  9. package/dist/node/alias.d.ts +3 -0
  10. package/dist/node/alias.d.ts.map +1 -0
  11. package/dist/node/alias.js +5 -0
  12. package/dist/node/bin.d.ts +2 -0
  13. package/dist/node/bin.d.ts.map +1 -0
  14. package/dist/node/bin.js +35 -0
  15. package/dist/node/build-serialize.d.ts +22 -0
  16. package/dist/node/build-serialize.d.ts.map +1 -0
  17. package/dist/node/build-serialize.js +36 -0
  18. package/dist/node/build.d.ts +3 -0
  19. package/dist/node/build.d.ts.map +1 -0
  20. package/dist/node/build.js +228 -0
  21. package/dist/node/builtin-plugins/pinceau-tokens.d.ts +7 -0
  22. package/dist/node/builtin-plugins/pinceau-tokens.d.ts.map +1 -0
  23. package/dist/node/builtin-plugins/pinceau-tokens.js +505 -0
  24. package/dist/node/builtin-plugins/tailwind-tokens.d.ts +6 -0
  25. package/dist/node/builtin-plugins/tailwind-tokens.d.ts.map +1 -0
  26. package/dist/node/builtin-plugins/tailwind-tokens.js +523 -0
  27. package/dist/node/builtin-plugins/vanilla-support/MountStory.d.ts +15 -0
  28. package/dist/node/builtin-plugins/vanilla-support/MountStory.d.ts.map +1 -0
  29. package/dist/node/builtin-plugins/vanilla-support/MountStory.js +39 -0
  30. package/dist/node/builtin-plugins/vanilla-support/RenderStory.d.ts +39 -0
  31. package/dist/node/builtin-plugins/vanilla-support/RenderStory.d.ts.map +1 -0
  32. package/dist/node/builtin-plugins/vanilla-support/RenderStory.js +129 -0
  33. package/dist/node/builtin-plugins/vanilla-support/client.d.ts +4 -0
  34. package/dist/node/builtin-plugins/vanilla-support/client.d.ts.map +1 -0
  35. package/dist/node/builtin-plugins/vanilla-support/client.js +5 -0
  36. package/dist/node/builtin-plugins/vanilla-support/collect.d.ts +3 -0
  37. package/dist/node/builtin-plugins/vanilla-support/collect.d.ts.map +1 -0
  38. package/dist/node/builtin-plugins/vanilla-support/collect.js +33 -0
  39. package/dist/node/builtin-plugins/vanilla-support/plugin.d.ts +3 -0
  40. package/dist/node/builtin-plugins/vanilla-support/plugin.d.ts.map +1 -0
  41. package/dist/node/builtin-plugins/vanilla-support/plugin.js +29 -0
  42. package/dist/node/builtin-plugins/vanilla-support/types.d.ts +36 -0
  43. package/dist/node/builtin-plugins/vanilla-support/types.d.ts.map +1 -0
  44. package/dist/node/builtin-plugins/vanilla-support/types.js +3 -0
  45. package/dist/node/builtin-plugins/vanilla-support/vanilla.story.d.ts +4 -0
  46. package/dist/node/builtin-plugins/vanilla-support/vanilla.story.d.ts.map +1 -0
  47. package/dist/node/builtin-plugins/vanilla-support/vanilla.story.js +55 -0
  48. package/dist/node/collect/index.d.ts +14 -0
  49. package/dist/node/collect/index.d.ts.map +1 -0
  50. package/dist/node/collect/index.js +129 -0
  51. package/dist/node/collect/run.d.ts +3 -0
  52. package/dist/node/collect/run.d.ts.map +1 -0
  53. package/dist/node/collect/run.js +7 -0
  54. package/dist/node/collect/worker.d.ts +14 -0
  55. package/dist/node/collect/worker.d.ts.map +1 -0
  56. package/dist/node/collect/worker.js +64 -0
  57. package/dist/node/colors.d.ts +287 -0
  58. package/dist/node/colors.d.ts.map +1 -0
  59. package/dist/node/colors.js +324 -0
  60. package/dist/node/commands/build.d.ts +5 -0
  61. package/dist/node/commands/build.d.ts.map +1 -0
  62. package/dist/node/commands/build.js +9 -0
  63. package/dist/node/commands/dev.d.ts +8 -0
  64. package/dist/node/commands/dev.d.ts.map +1 -0
  65. package/dist/node/commands/dev.js +52 -0
  66. package/dist/node/commands/preview.d.ts +5 -0
  67. package/dist/node/commands/preview.d.ts.map +1 -0
  68. package/dist/node/commands/preview.js +15 -0
  69. package/dist/node/config.d.ts +40 -0
  70. package/dist/node/config.d.ts.map +1 -0
  71. package/dist/node/config.js +330 -0
  72. package/dist/node/context.d.ts +18 -0
  73. package/dist/node/context.d.ts.map +1 -0
  74. package/dist/node/context.js +28 -0
  75. package/dist/node/dom/dom-keys.d.ts +5 -0
  76. package/dist/node/dom/dom-keys.d.ts.map +1 -0
  77. package/dist/node/dom/dom-keys.js +233 -0
  78. package/dist/node/dom/env.d.ts +5 -0
  79. package/dist/node/dom/env.d.ts.map +1 -0
  80. package/dist/node/dom/env.js +47 -0
  81. package/dist/node/dom/util.d.ts +11 -0
  82. package/dist/node/dom/util.d.ts.map +1 -0
  83. package/dist/node/dom/util.js +65 -0
  84. package/dist/node/index.d.ts +12 -0
  85. package/dist/node/index.d.ts.map +1 -0
  86. package/dist/node/index.js +4 -0
  87. package/dist/node/load.d.ts +9 -0
  88. package/dist/node/load.d.ts.map +1 -0
  89. package/dist/node/load.js +42 -0
  90. package/dist/node/markdown.d.ts +11 -0
  91. package/dist/node/markdown.d.ts.map +1 -0
  92. package/dist/node/markdown.js +228 -0
  93. package/dist/node/plugin.d.ts +42 -0
  94. package/dist/node/plugin.d.ts.map +1 -0
  95. package/dist/node/plugin.js +67 -0
  96. package/dist/node/preview.d.ts +8 -0
  97. package/dist/node/preview.d.ts.map +1 -0
  98. package/dist/node/preview.js +41 -0
  99. package/dist/node/search.d.ts +17 -0
  100. package/dist/node/search.d.ts.map +1 -0
  101. package/dist/node/search.js +72 -0
  102. package/dist/node/server.d.ts +12 -0
  103. package/dist/node/server.d.ts.map +1 -0
  104. package/dist/node/server.js +189 -0
  105. package/dist/node/stories.d.ts +22 -0
  106. package/dist/node/stories.d.ts.map +1 -0
  107. package/dist/node/stories.js +125 -0
  108. package/dist/node/tree.d.ts +4 -0
  109. package/dist/node/tree.d.ts.map +1 -0
  110. package/dist/node/tree.js +117 -0
  111. package/dist/node/util/find-up.d.ts +2 -0
  112. package/dist/node/util/find-up.d.ts.map +1 -0
  113. package/dist/node/util/find-up.js +20 -0
  114. package/dist/node/util/fs.d.ts +2 -0
  115. package/dist/node/util/fs.d.ts.map +1 -0
  116. package/dist/node/util/fs.js +1 -0
  117. package/dist/node/util/log.d.ts +2 -0
  118. package/dist/node/util/log.d.ts.map +1 -0
  119. package/dist/node/util/log.js +9 -0
  120. package/dist/node/util/slugify.d.ts +2 -0
  121. package/dist/node/util/slugify.d.ts.map +1 -0
  122. package/dist/node/util/slugify.js +22 -0
  123. package/dist/node/util/vendors.d.ts +3 -0
  124. package/dist/node/util/vendors.d.ts.map +1 -0
  125. package/dist/node/util/vendors.js +22 -0
  126. package/dist/node/vendors/controls.d.ts +2 -0
  127. package/dist/node/vendors/controls.d.ts.map +1 -0
  128. package/dist/node/vendors/controls.js +1 -0
  129. package/dist/node/vendors/vue.d.ts +2 -0
  130. package/dist/node/vendors/vue.d.ts.map +1 -0
  131. package/dist/node/vendors/vue.js +1 -0
  132. package/dist/node/virtual/index.d.ts +38 -0
  133. package/dist/node/virtual/index.d.ts.map +1 -0
  134. package/dist/node/virtual/index.js +49 -0
  135. package/dist/node/virtual/markdown.d.ts +3 -0
  136. package/dist/node/virtual/markdown.d.ts.map +1 -0
  137. package/dist/node/virtual/markdown.js +19 -0
  138. package/dist/node/virtual/noop.d.ts +2 -0
  139. package/dist/node/virtual/noop.d.ts.map +1 -0
  140. package/dist/node/virtual/noop.js +1 -0
  141. package/dist/node/virtual/resolved-commands.d.ts +3 -0
  142. package/dist/node/virtual/resolved-commands.d.ts.map +1 -0
  143. package/dist/node/virtual/resolved-commands.js +32 -0
  144. package/dist/node/virtual/resolved-config.d.ts +3 -0
  145. package/dist/node/virtual/resolved-config.d.ts.map +1 -0
  146. package/dist/node/virtual/resolved-config.js +10 -0
  147. package/dist/node/virtual/resolved-generated-global-setup.d.ts +3 -0
  148. package/dist/node/virtual/resolved-generated-global-setup.d.ts.map +1 -0
  149. package/dist/node/virtual/resolved-generated-global-setup.js +23 -0
  150. package/dist/node/virtual/resolved-generated-setup-code.d.ts +3 -0
  151. package/dist/node/virtual/resolved-generated-setup-code.d.ts.map +1 -0
  152. package/dist/node/virtual/resolved-generated-setup-code.js +5 -0
  153. package/dist/node/virtual/resolved-markdown-files.d.ts +3 -0
  154. package/dist/node/virtual/resolved-markdown-files.d.ts.map +1 -0
  155. package/dist/node/virtual/resolved-markdown-files.js +17 -0
  156. package/dist/node/virtual/resolved-stories.d.ts +3 -0
  157. package/dist/node/virtual/resolved-stories.d.ts.map +1 -0
  158. package/dist/node/virtual/resolved-stories.js +42 -0
  159. package/dist/node/virtual/resolved-support-plugins-client.d.ts +3 -0
  160. package/dist/node/virtual/resolved-support-plugins-client.d.ts.map +1 -0
  161. package/dist/node/virtual/resolved-support-plugins-client.js +11 -0
  162. package/dist/node/virtual/resolved-support-plugins-collect.d.ts +3 -0
  163. package/dist/node/virtual/resolved-support-plugins-collect.d.ts.map +1 -0
  164. package/dist/node/virtual/resolved-support-plugins-collect.js +11 -0
  165. package/dist/node/virtual/resolved-theme.d.ts +3 -0
  166. package/dist/node/virtual/resolved-theme.d.ts.map +1 -0
  167. package/dist/node/virtual/resolved-theme.js +12 -0
  168. package/dist/node/virtual/story-source.d.ts +3 -0
  169. package/dist/node/virtual/story-source.d.ts.map +1 -0
  170. package/dist/node/virtual/story-source.js +16 -0
  171. package/dist/node/virtual/story.d.ts +3 -0
  172. package/dist/node/virtual/story.d.ts.map +1 -0
  173. package/dist/node/virtual/story.js +7 -0
  174. package/dist/node/virtual/util.d.ts +3 -0
  175. package/dist/node/virtual/util.d.ts.map +1 -0
  176. package/dist/node/virtual/util.js +4 -0
  177. package/dist/node/virtual/vite-plugin.d.ts +4 -0
  178. package/dist/node/virtual/vite-plugin.d.ts.map +1 -0
  179. package/dist/node/virtual/vite-plugin.js +126 -0
  180. package/dist/node/vite.d.ts +9 -0
  181. package/dist/node/vite.d.ts.map +1 -0
  182. package/dist/node/vite.js +337 -0
  183. package/index.d.ts +1 -0
  184. package/package.json +89 -0
  185. package/plugin.d.ts +3 -0
  186. package/plugin.js +11 -0
  187. package/src/controls.ts +1 -0
  188. package/src/node/__tests__/markdown/test1.story.md +7 -0
  189. package/src/node/__tests__/markdown/test2.story.md +5 -0
  190. package/src/node/__tests__/markdown.spec.ts +61 -0
  191. package/src/node/__tests__/tree.spec.ts +109 -0
  192. package/src/node/alias.ts +8 -0
  193. package/src/node/bin.ts +43 -0
  194. package/src/node/build-serialize.ts +62 -0
  195. package/src/node/build.ts +283 -0
  196. package/src/node/builtin-plugins/pinceau-tokens.ts +521 -0
  197. package/src/node/builtin-plugins/tailwind-tokens.ts +536 -0
  198. package/src/node/builtin-plugins/vanilla-support/MountStory.ts +49 -0
  199. package/src/node/builtin-plugins/vanilla-support/RenderStory.ts +164 -0
  200. package/src/node/builtin-plugins/vanilla-support/client.ts +6 -0
  201. package/src/node/builtin-plugins/vanilla-support/collect.ts +43 -0
  202. package/src/node/builtin-plugins/vanilla-support/plugin.ts +35 -0
  203. package/src/node/builtin-plugins/vanilla-support/types.ts +40 -0
  204. package/src/node/builtin-plugins/vanilla-support/vanilla.story.ts +63 -0
  205. package/src/node/collect/index.ts +160 -0
  206. package/src/node/collect/run.ts +9 -0
  207. package/src/node/collect/worker.ts +97 -0
  208. package/src/node/colors.ts +340 -0
  209. package/src/node/commands/build.ts +14 -0
  210. package/src/node/commands/dev.ts +67 -0
  211. package/src/node/commands/preview.ts +22 -0
  212. package/src/node/config.ts +385 -0
  213. package/src/node/context.ts +60 -0
  214. package/src/node/dom/dom-keys.ts +238 -0
  215. package/src/node/dom/env.ts +60 -0
  216. package/src/node/dom/util.ts +83 -0
  217. package/src/node/index.ts +12 -0
  218. package/src/node/load.ts +59 -0
  219. package/src/node/markdown.ts +267 -0
  220. package/src/node/plugin.ts +95 -0
  221. package/src/node/preview.ts +57 -0
  222. package/src/node/search.ts +84 -0
  223. package/src/node/server.ts +235 -0
  224. package/src/node/stories.ts +154 -0
  225. package/src/node/tree.ts +158 -0
  226. package/src/node/util/find-up.ts +24 -0
  227. package/src/node/util/fs.ts +1 -0
  228. package/src/node/util/log.ts +10 -0
  229. package/src/node/util/slugify.ts +26 -0
  230. package/src/node/util/vendors.ts +27 -0
  231. package/src/node/vendors/controls.ts +1 -0
  232. package/src/node/vendors/vue.ts +1 -0
  233. package/src/node/virtual/index.ts +50 -0
  234. package/src/node/virtual/markdown.ts +21 -0
  235. package/src/node/virtual/noop.ts +1 -0
  236. package/src/node/virtual/resolved-commands.ts +42 -0
  237. package/src/node/virtual/resolved-config.ts +12 -0
  238. package/src/node/virtual/resolved-generated-global-setup.ts +25 -0
  239. package/src/node/virtual/resolved-generated-setup-code.ts +7 -0
  240. package/src/node/virtual/resolved-markdown-files.ts +19 -0
  241. package/src/node/virtual/resolved-stories.ts +44 -0
  242. package/src/node/virtual/resolved-support-plugins-client.ts +14 -0
  243. package/src/node/virtual/resolved-support-plugins-collect.ts +14 -0
  244. package/src/node/virtual/resolved-theme.ts +14 -0
  245. package/src/node/virtual/story-source.ts +18 -0
  246. package/src/node/virtual/story.ts +9 -0
  247. package/src/node/virtual/util.ts +5 -0
  248. package/src/node/virtual/vite-plugin.ts +146 -0
  249. package/src/node/vite.ts +379 -0
  250. package/tsconfig.json +44 -0
  251. package/vitest.config.ts +10 -0
@@ -0,0 +1,109 @@
1
+ import type { ServerStoryFile } from '@poveste/shared'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { getDefaultConfig } from '../config.js'
4
+ import { makeTree } from '../tree.js'
5
+
6
+ let id = 0
7
+
8
+ interface StoryFileFactoryOptions {
9
+ treePath: string[]
10
+ }
11
+
12
+ function storyFileFactory(options: StoryFileFactoryOptions): ServerStoryFile {
13
+ return {
14
+ id: `id_${id++}`,
15
+ path: options.treePath.join('/'),
16
+ treePath: options.treePath,
17
+ fileName: 'fileName',
18
+ moduleId: 'moduleId',
19
+ relativePath: options.treePath.join('/'),
20
+ supportPluginId: 'supportPluginId',
21
+ }
22
+ }
23
+
24
+ describe('makeTree', () => {
25
+ it('should create an ascending ordered tree', () => {
26
+ const config = getDefaultConfig()
27
+ const files = [
28
+ { treePath: ['hi'] },
29
+ { treePath: ['hey'] },
30
+ { treePath: ['hello', 'world'] },
31
+ { treePath: ['hello', 'mom'] },
32
+ ]
33
+
34
+ const tree = makeTree(config, files.map(storyFileFactory))
35
+
36
+ expect(tree).toEqual([
37
+ {
38
+ title: 'hello',
39
+ children: [
40
+ { title: 'mom', index: 3 },
41
+ { title: 'world', index: 2 },
42
+ ],
43
+ },
44
+ { title: 'hey', index: 1 },
45
+ { title: 'hi', index: 0 },
46
+ ])
47
+ })
48
+
49
+ it('should handle title conflict', () => {
50
+ const config = getDefaultConfig()
51
+ const files = [
52
+ { treePath: ['hi'] },
53
+ { treePath: ['hi'] },
54
+ { treePath: ['hi'] },
55
+ ]
56
+
57
+ const tree = makeTree(config, files.map(storyFileFactory))
58
+
59
+ expect(tree).toEqual([
60
+ { title: 'hi', index: 0 },
61
+ { title: 'hi-1', index: 1 },
62
+ { title: 'hi-2', index: 2 },
63
+ ])
64
+ })
65
+
66
+ it('should handle file-folder conflict when folder in first', () => {
67
+ const config = getDefaultConfig()
68
+ const files = [
69
+ { treePath: ['hi', 'dad'] },
70
+ { treePath: ['hi'] },
71
+ { treePath: ['hi', 'mom'] },
72
+ ]
73
+
74
+ const tree = makeTree(config, files.map(storyFileFactory))
75
+
76
+ expect(tree).toEqual([
77
+ {
78
+ title: 'hi',
79
+ children: [
80
+ { title: 'dad', index: 0 },
81
+ { title: 'mom', index: 2 },
82
+ ],
83
+ },
84
+ { title: 'hi-1', index: 1 },
85
+ ])
86
+ })
87
+
88
+ it('should handle file-folder conflict when file in first', () => {
89
+ const config = getDefaultConfig()
90
+ const files = [
91
+ { treePath: ['hi'] },
92
+ { treePath: ['hi', 'dad'] },
93
+ { treePath: ['hi', 'mom'] },
94
+ ]
95
+
96
+ const tree = makeTree(config, files.map(storyFileFactory))
97
+
98
+ expect(tree).toEqual([
99
+ {
100
+ title: 'hi',
101
+ children: [
102
+ { title: 'dad', index: 1 },
103
+ { title: 'mom', index: 2 },
104
+ ],
105
+ },
106
+ { title: 'hi-1', index: 0 },
107
+ ])
108
+ })
109
+ })
@@ -0,0 +1,8 @@
1
+ import { createRequire } from 'node:module'
2
+ import path from 'pathe'
3
+
4
+ const require = createRequire(import.meta.url)
5
+
6
+ export const APP_PATH = path.join(path.dirname(require.resolve('@poveste/app/package.json')), process.env.HISTOIRE_DEV ? 'src' : 'dist')
7
+
8
+ export const TEMP_PATH = path.join(process.cwd(), 'node_modules', '.histoire')
@@ -0,0 +1,43 @@
1
+ import fs from 'node:fs'
2
+ import { fileURLToPath } from 'node:url'
3
+ import { dirname, resolve } from 'pathe'
4
+ import sade from 'sade'
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url))
7
+
8
+ const { version } = JSON.parse(fs.readFileSync(resolve(__dirname, '../../package.json'), 'utf8'))
9
+
10
+ process.env.NODE_ENV = 'development'
11
+ process.env.HISTOIRE = 'true'
12
+
13
+ const program = sade('poveste')
14
+ program.version(version)
15
+
16
+ program.command('dev')
17
+ .describe('open the stories in your browser for development')
18
+ .option('-p, --port <port>', 'Listening port of the server')
19
+ .option('-c, --config <file>', `[string] use specified config file`)
20
+ .option('--open', 'Open in your default browser')
21
+ .option('--host <host>', '[string] specify hostname')
22
+ .action(async (options) => {
23
+ const { devCommand } = await import('./commands/dev.js')
24
+ return devCommand(options)
25
+ })
26
+
27
+ program.command('build')
28
+ .describe('build the histoire final app you can deploy')
29
+ .option('-c, --config <file>', `[string] use specified config file`)
30
+ .action(async (options) => {
31
+ const { buildCommand } = await import('./commands/build.js')
32
+ return buildCommand(options)
33
+ })
34
+
35
+ program.command('preview')
36
+ .describe('preview the built directory')
37
+ .option('-p, --port <port>', 'Listening port of the server')
38
+ .action(async (options) => {
39
+ const { previewCommand } = await import('./commands/preview.js')
40
+ return previewCommand(options)
41
+ })
42
+
43
+ program.parse(process.argv)
@@ -0,0 +1,62 @@
1
+ import type { ServerStory } from '@poveste/shared'
2
+ import type { Context } from './context.js'
3
+
4
+ interface SerializedStory extends Omit<ServerStory, 'docsText'> {
5
+ relativePath: string
6
+ supportPluginId: string
7
+ treePath?: string[]
8
+ virtual?: boolean
9
+ markdownFile?: SerializedMarkdownFile
10
+ }
11
+
12
+ interface SerializedMarkdownFile {
13
+ id: string
14
+ relativePath: string
15
+ isRelatedToStory: boolean
16
+ frontmatter?: any
17
+ }
18
+
19
+ interface SerializedStoryData {
20
+ stories: SerializedStory[]
21
+ markdownFiles: SerializedMarkdownFile[]
22
+ }
23
+
24
+ export function getSerializedStoryData(ctx: Context): SerializedStoryData {
25
+ const data: SerializedStoryData = {
26
+ stories: [],
27
+ markdownFiles: [],
28
+ }
29
+
30
+ for (const storyFile of ctx.storyFiles) {
31
+ if (storyFile.story) {
32
+ data.stories.push({
33
+ ...Object.assign({}, storyFile.story, {
34
+ docsText: undefined,
35
+ }),
36
+ relativePath: storyFile.relativePath,
37
+ supportPluginId: storyFile.supportPluginId,
38
+ treePath: storyFile.treePath,
39
+ virtual: storyFile.virtual,
40
+ markdownFile: storyFile.markdownFile
41
+ ? {
42
+ id: storyFile.markdownFile.id,
43
+ relativePath: storyFile.markdownFile.relativePath,
44
+ isRelatedToStory: storyFile.markdownFile.isRelatedToStory,
45
+ frontmatter: storyFile.markdownFile.frontmatter,
46
+ }
47
+ : null,
48
+ })
49
+ }
50
+ }
51
+
52
+ for (const markdownFile of ctx.markdownFiles) {
53
+ data.markdownFiles.push({
54
+ id: markdownFile.id,
55
+ relativePath: markdownFile.relativePath,
56
+ isRelatedToStory: markdownFile.isRelatedToStory,
57
+ frontmatter: markdownFile.frontmatter,
58
+ })
59
+ }
60
+
61
+ return data
62
+ }
@@ -0,0 +1,283 @@
1
+ import type {
2
+ BuildEndCallback,
3
+ ChangeViteConfigCallback,
4
+ PreviewStoryCallback,
5
+ } from '@poveste/shared'
6
+ import type { RollupOutput } from 'rollup'
7
+ import type {
8
+ InlineConfig as ViteInlineConfig,
9
+ Plugin as VitePlugin,
10
+ } from 'vite'
11
+ import type { Context } from './context.js'
12
+ import { performance } from 'node:perf_hooks'
13
+ import fs from 'fs-extra'
14
+ import { lookup as lookupMime } from 'mrmime'
15
+ import { join } from 'pathe'
16
+ import pc from 'picocolors'
17
+ import {
18
+ createServer as createViteServer,
19
+ mergeConfig as mergeViteConfig,
20
+ build as viteBuild,
21
+ } from 'vite'
22
+ import { APP_PATH } from './alias.js'
23
+ import { getSerializedStoryData } from './build-serialize.js'
24
+ import { useCollectStories } from './collect/index.js'
25
+ import { useModuleLoader } from './load.js'
26
+ import { createMarkdownFilesWatcher } from './markdown.js'
27
+ import { BuildPluginApi } from './plugin.js'
28
+ import { startPreview } from './preview.js'
29
+ import { findAllStories } from './stories.js'
30
+ import { getViteConfigWithPlugins } from './vite.js'
31
+
32
+ const PRELOAD_MODULES = [
33
+ 'vendor',
34
+ ]
35
+
36
+ const PREFETCHED_MODULES = [
37
+ 'StoryView',
38
+ 'reactivity',
39
+ 'global-components',
40
+ ]
41
+
42
+ export async function build(ctx: Context) {
43
+ const startTime = performance.now()
44
+ await findAllStories(ctx)
45
+
46
+ // Scan for markdown files
47
+ {
48
+ const { stop } = await createMarkdownFilesWatcher(ctx)
49
+ await stop()
50
+ }
51
+
52
+ const { viteConfig } = await getViteConfigWithPlugins(true, ctx)
53
+ const server = await createViteServer(
54
+ mergeViteConfig(viteConfig, {
55
+ optimizeDeps: { include: [], noDiscovery: true },
56
+ }),
57
+ )
58
+ await server.pluginContainer.buildStart({})
59
+
60
+ const moduleLoader = useModuleLoader({
61
+ server,
62
+ throws: true,
63
+ })
64
+ const changeViteConfigCallbacks: ChangeViteConfigCallback[] = []
65
+ const buildEndCallbacks: BuildEndCallback[] = []
66
+ const previewStoryCallbacks: PreviewStoryCallback[] = []
67
+ for (const plugin of ctx.config.plugins) {
68
+ if (plugin.onBuild) {
69
+ const api = new BuildPluginApi(ctx, plugin, moduleLoader)
70
+ await plugin.onBuild(api)
71
+ changeViteConfigCallbacks.push(...api.changeViteConfigCallbacks)
72
+ buildEndCallbacks.push(...api.buildEndCallbacks)
73
+ previewStoryCallbacks.push(...api.previewStoryCallbacks)
74
+ }
75
+ }
76
+
77
+ // Collect story data
78
+ const { executeStoryFile, destroy: destroyCollectStories } = useCollectStories({
79
+ server,
80
+ throws: true,
81
+ }, ctx)
82
+ await Promise.all(ctx.storyFiles.map(storyFile => executeStoryFile(storyFile)))
83
+ await destroyCollectStories()
84
+
85
+ const storyCount = ctx.storyFiles.reduce((sum, file) => sum + (file.story?.variants.length ? 1 : 0), 0)
86
+ const variantCount = ctx.storyFiles.reduce((sum, file) => sum + (file.story?.variants.length ?? 0), 0)
87
+ const emptyStoryCount = ctx.storyFiles.length - storyCount
88
+
89
+ const { viteConfig: buildViteConfigRaw } = await getViteConfigWithPlugins(false, ctx)
90
+ const buildViteConfig: ViteInlineConfig = mergeViteConfig(buildViteConfigRaw, {
91
+ mode: 'development',
92
+ build: {
93
+ lib: false,
94
+ rollupOptions: {
95
+ input: [
96
+ join(APP_PATH, 'bundle-main.js'),
97
+ join(APP_PATH, 'bundle-sandbox.js'),
98
+ ],
99
+ plugins: [
100
+ {
101
+ name: 'histoire-build-rollup-options-override',
102
+ enforce: 'post',
103
+ options(options) {
104
+ // Don't externalize
105
+ options.external = []
106
+ },
107
+ },
108
+ ],
109
+ },
110
+ },
111
+ })
112
+
113
+ // For @vite/plugin-vue: Always put our vite server
114
+ // Disable template inlining
115
+ // (so that we no longer need defineExpose)
116
+ // Nuxt: replaces the Nuxt vite dev server
117
+ buildViteConfig.plugins.push({
118
+ name: 'histoire-vue-plugin-override',
119
+ config(config) {
120
+ const vuePlugin = config.plugins.find((p: any) => p.name === 'vite:vue') as VitePlugin
121
+ if (vuePlugin) {
122
+ // @ts-expect-error vue plugin use function form
123
+ const original = vuePlugin.configureServer.bind(vuePlugin)
124
+ vuePlugin.configureServer = () => {
125
+ original({
126
+ ...server,
127
+ config: {
128
+ ...server.config,
129
+ server: {
130
+ ...server.config.server,
131
+ hmr: false,
132
+ },
133
+ },
134
+ })
135
+ }
136
+ // @ts-expect-error vue plugin use function form
137
+ vuePlugin.configureServer(server)
138
+ }
139
+ },
140
+ })
141
+
142
+ buildViteConfig.plugins.push({
143
+ name: 'histoire-build-config-override',
144
+ enforce: 'post',
145
+ config(config) {
146
+ // Don't externalize
147
+ config.build.rollupOptions.external = []
148
+
149
+ // Force chunk strategy
150
+ config.build.rollupOptions.output = {
151
+ manualChunks(id) {
152
+ if (!id.includes('@poveste/app') && id.includes('node_modules')) {
153
+ for (const test of ctx.config.build?.excludeFromVendorsChunk ?? []) {
154
+ if ((
155
+ typeof test === 'string' && id.includes(test)
156
+ ) || (
157
+ test instanceof RegExp && test.test(id)
158
+ )) {
159
+ // Excluded from vendor chunk
160
+ return
161
+ }
162
+ }
163
+ return 'vendor'
164
+ }
165
+ },
166
+ }
167
+
168
+ // Force vite build options
169
+ Object.assign(config.build, {
170
+ outDir: ctx.config.outDir,
171
+ emptyOutDir: true,
172
+ cssCodeSplit: false,
173
+ minify: false,
174
+ // Don't build in SSR mode
175
+ ssr: false,
176
+ })
177
+
178
+ config.define.__HST_COLLECT__ = false
179
+ },
180
+ })
181
+
182
+ for (const cb of changeViteConfigCallbacks) {
183
+ console.log('vite config hook', cb)
184
+ await cb(buildViteConfig)
185
+ }
186
+
187
+ const results = await viteBuild(buildViteConfig)
188
+ const result = Array.isArray(results) ? results[0] : results as RollupOutput
189
+
190
+ const styleOutput = result.output.find(o => o.name === 'style.css' && o.type === 'asset')
191
+
192
+ // Preload
193
+ const preloadOutputs = result.output.filter(o => PRELOAD_MODULES.includes(o.name) && o.type === 'chunk')
194
+ const preloadHtml = generateScriptLinks(preloadOutputs.map(o => o.fileName), 'preload', ctx)
195
+
196
+ // Prefetch
197
+ const prefetchOutputs = result.output.filter(o => PREFETCHED_MODULES.includes(o.name) && o.type === 'chunk')
198
+ const prefetchHtml = generateScriptLinks(prefetchOutputs.map(o => o.fileName), 'prefetch', ctx)
199
+
200
+ // Index
201
+ const indexOutput = result.output.find(o => o.name === 'bundle-main' && o.type === 'chunk')
202
+ const indexHtml = generateEntryHtml(indexOutput.fileName, styleOutput.fileName, {
203
+ HEAD: `${preloadHtml}${prefetchHtml}`,
204
+ }, ctx)
205
+ await writeFile('index.html', indexHtml, ctx)
206
+
207
+ // Sandbox
208
+ const sandboxOutput = result.output.find(o => o.name === 'bundle-sandbox' && o.type === 'chunk')
209
+ const sandboxHtml = generateEntryHtml(sandboxOutput.fileName, styleOutput.fileName, {}, ctx)
210
+ await writeFile('__sandbox.html', sandboxHtml, ctx)
211
+
212
+ await writeFile('histoire.json', JSON.stringify(getSerializedStoryData(ctx), null, 2), ctx)
213
+
214
+ const duration = performance.now() - startTime
215
+ if (emptyStoryCount) {
216
+ console.warn(pc.yellow(`⚠️ ${emptyStoryCount} empty story file${emptyStoryCount === 1 ? '' : 's'}`))
217
+ }
218
+ console.log(pc.green(`✅ Built ${storyCount} stor${storyCount === 1 ? 'y' : 'ies'} (${variantCount} variant${variantCount === 1 ? '' : 's'}) in ${Math.round(duration / 1000 * 100) / 100}s`))
219
+
220
+ // Render
221
+ if (previewStoryCallbacks.length) {
222
+ const { baseUrl, close } = await startPreview(null, ctx)
223
+ for (const storyFile of ctx.storyFiles) {
224
+ const story = storyFile.story
225
+ for (const variant of story.variants) {
226
+ const query = new URLSearchParams()
227
+ query.append('storyId', story.id)
228
+ query.append('variantId', variant.id)
229
+ const url = `${baseUrl}__sandbox.html?${query.toString()}`
230
+ for (const fn of previewStoryCallbacks) {
231
+ await fn({
232
+ file: storyFile.path,
233
+ story,
234
+ variant,
235
+ url,
236
+ })
237
+ }
238
+ }
239
+ }
240
+ await close()
241
+ }
242
+
243
+ await server.close()
244
+
245
+ for (const fn of buildEndCallbacks) {
246
+ await fn()
247
+ }
248
+ }
249
+
250
+ function generateBaseHtml(head: string, body: string, ctx: Context) {
251
+ return `<!DOCTYPE html>
252
+ <html>
253
+ <head>
254
+ <title>${ctx.config.theme.title}</title>
255
+ <meta charset="utf-8">
256
+ <meta name="viewport" content="width=device-width,initial-scale=1">
257
+ <meta name="description" content="">
258
+ ${head}
259
+ </head>
260
+ <body>
261
+ ${body}
262
+ </body>
263
+ </html>`
264
+ }
265
+
266
+ function generateEntryHtml(jsEntryFile: string, cssEntryFile: string, variables: { HEAD?: string }, ctx: Context) {
267
+ return generateBaseHtml(
268
+ `<link rel="stylesheet" href="${ctx.resolvedViteConfig.base}${cssEntryFile}">
269
+ ${ctx.config.theme?.favicon ? `<link rel="icon" type="${lookupMime(ctx.config.theme.favicon)}" href="${ctx.resolvedViteConfig.base}${ctx.config.theme.favicon}"/>` : ''}
270
+ ${variables.HEAD ?? ''}`,
271
+ `<div id="app"></div>
272
+ <script type="module" src="${ctx.resolvedViteConfig.base}${jsEntryFile}"></script>`,
273
+ ctx,
274
+ )
275
+ }
276
+
277
+ async function writeFile(fileName: string, content: string, ctx: Context) {
278
+ await fs.writeFile(join(ctx.config.outDir, fileName), content, 'utf8')
279
+ }
280
+
281
+ function generateScriptLinks(prefetchScripts: string[], rel: string, ctx: Context) {
282
+ return prefetchScripts.map(s => `<link rel="${rel}" href="${ctx.resolvedViteConfig.base}${s}" as="script" crossOrigin="anonymous">`).join('')
283
+ }