@quilted/rollup 0.1.18 → 0.2.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 (126) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/esm/app.mjs +442 -233
  3. package/build/esm/constants.mjs +5 -5
  4. package/build/esm/features/assets.mjs +93 -81
  5. package/build/esm/features/async.mjs +186 -0
  6. package/build/esm/features/css.mjs +26 -39
  7. package/build/esm/features/env.mjs +47 -44
  8. package/build/esm/features/esnext.mjs +57 -0
  9. package/build/esm/features/graphql/transform.mjs +60 -56
  10. package/build/esm/features/graphql.mjs +65 -47
  11. package/build/esm/features/request-router.mjs +6 -4
  12. package/build/esm/features/source-code.mjs +54 -28
  13. package/build/esm/features/system-js.mjs +13 -18
  14. package/build/esm/features/typescript.mjs +13 -10
  15. package/build/esm/features/workers.mjs +173 -0
  16. package/build/esm/index.mjs +3 -2
  17. package/build/esm/module.mjs +69 -62
  18. package/build/esm/package.mjs +275 -84
  19. package/build/esm/server.mjs +118 -0
  20. package/build/esm/shared/browserslist.mjs +141 -16
  21. package/build/esm/shared/magic-module.mjs +9 -7
  22. package/build/esm/shared/package-json.mjs +7 -1
  23. package/build/esm/shared/path.mjs +7 -0
  24. package/build/esm/shared/rollup.mjs +89 -25
  25. package/build/esm/shared/strings.mjs +7 -6
  26. package/build/tsconfig.tsbuildinfo +1 -1
  27. package/build/typescript/app.d.ts +126 -27
  28. package/build/typescript/app.d.ts.map +1 -1
  29. package/build/typescript/features/assets.d.ts +1 -2
  30. package/build/typescript/features/assets.d.ts.map +1 -1
  31. package/build/typescript/features/async.d.ts +10 -0
  32. package/build/typescript/features/async.d.ts.map +1 -0
  33. package/build/typescript/features/css.d.ts +2 -1
  34. package/build/typescript/features/css.d.ts.map +1 -1
  35. package/build/typescript/features/env.d.ts +1 -0
  36. package/build/typescript/features/env.d.ts.map +1 -1
  37. package/build/typescript/features/esnext.d.ts +9 -0
  38. package/build/typescript/features/esnext.d.ts.map +1 -0
  39. package/build/typescript/features/graphql.d.ts +2 -2
  40. package/build/typescript/features/graphql.d.ts.map +1 -1
  41. package/build/typescript/features/source-code.d.ts +9 -3
  42. package/build/typescript/features/source-code.d.ts.map +1 -1
  43. package/build/typescript/features/workers.d.ts +52 -0
  44. package/build/typescript/features/workers.d.ts.map +1 -0
  45. package/build/typescript/index.d.ts +3 -2
  46. package/build/typescript/index.d.ts.map +1 -1
  47. package/build/typescript/module.d.ts +24 -6
  48. package/build/typescript/module.d.ts.map +1 -1
  49. package/build/typescript/package.d.ts +196 -4
  50. package/build/typescript/package.d.ts.map +1 -1
  51. package/build/typescript/server.d.ts +98 -0
  52. package/build/typescript/server.d.ts.map +1 -0
  53. package/build/typescript/shared/browserslist.d.ts +20 -3
  54. package/build/typescript/shared/browserslist.d.ts.map +1 -1
  55. package/build/typescript/shared/path.d.ts +2 -0
  56. package/build/typescript/shared/path.d.ts.map +1 -0
  57. package/build/typescript/shared/rollup.d.ts +27 -1
  58. package/build/typescript/shared/rollup.d.ts.map +1 -1
  59. package/configuration/rollup.config.js +40 -0
  60. package/package.json +61 -8
  61. package/source/app.ts +472 -109
  62. package/source/features/assets.ts +5 -7
  63. package/source/features/async.ts +249 -0
  64. package/source/features/css.ts +4 -2
  65. package/source/features/env.ts +6 -0
  66. package/source/features/esnext.ts +70 -0
  67. package/source/features/graphql.ts +4 -2
  68. package/source/features/source-code.ts +26 -8
  69. package/source/features/workers.ts +292 -0
  70. package/source/index.ts +4 -0
  71. package/source/module.ts +45 -19
  72. package/source/package.ts +394 -36
  73. package/source/server.ts +245 -0
  74. package/source/shared/browserslist.ts +208 -18
  75. package/source/shared/path.ts +5 -0
  76. package/source/shared/rollup.ts +102 -4
  77. package/tsconfig.json +6 -2
  78. package/build/cjs/app.cjs +0 -456
  79. package/build/cjs/constants.cjs +0 -13
  80. package/build/cjs/features/assets.cjs +0 -240
  81. package/build/cjs/features/css.cjs +0 -71
  82. package/build/cjs/features/env.cjs +0 -135
  83. package/build/cjs/features/graphql/transform.cjs +0 -186
  84. package/build/cjs/features/graphql.cjs +0 -86
  85. package/build/cjs/features/request-router.cjs +0 -31
  86. package/build/cjs/features/source-code.cjs +0 -54
  87. package/build/cjs/features/system-js.cjs +0 -36
  88. package/build/cjs/features/typescript.cjs +0 -56
  89. package/build/cjs/index.cjs +0 -13
  90. package/build/cjs/module.cjs +0 -121
  91. package/build/cjs/package.cjs +0 -170
  92. package/build/cjs/shared/browserslist.cjs +0 -25
  93. package/build/cjs/shared/magic-module.cjs +0 -32
  94. package/build/cjs/shared/package-json.cjs +0 -31
  95. package/build/cjs/shared/rollup.cjs +0 -72
  96. package/build/cjs/shared/strings.cjs +0 -16
  97. package/build/esnext/app.esnext +0 -429
  98. package/build/esnext/constants.esnext +0 -7
  99. package/build/esnext/features/assets.esnext +0 -215
  100. package/build/esnext/features/css.esnext +0 -69
  101. package/build/esnext/features/env.esnext +0 -112
  102. package/build/esnext/features/graphql/transform.esnext +0 -181
  103. package/build/esnext/features/graphql.esnext +0 -84
  104. package/build/esnext/features/request-router.esnext +0 -29
  105. package/build/esnext/features/source-code.esnext +0 -51
  106. package/build/esnext/features/system-js.esnext +0 -33
  107. package/build/esnext/features/typescript.esnext +0 -34
  108. package/build/esnext/index.esnext +0 -3
  109. package/build/esnext/module.esnext +0 -100
  110. package/build/esnext/package.esnext +0 -148
  111. package/build/esnext/shared/browserslist.esnext +0 -23
  112. package/build/esnext/shared/magic-module.esnext +0 -30
  113. package/build/esnext/shared/package-json.esnext +0 -10
  114. package/build/esnext/shared/rollup.esnext +0 -49
  115. package/build/esnext/shared/strings.esnext +0 -14
  116. package/build/typescript/env.d.ts +0 -55
  117. package/build/typescript/env.d.ts.map +0 -1
  118. package/build/typescript/graphql/transform.d.ts +0 -17
  119. package/build/typescript/graphql/transform.d.ts.map +0 -1
  120. package/build/typescript/graphql.d.ts +0 -6
  121. package/build/typescript/graphql.d.ts.map +0 -1
  122. package/build/typescript/request-router.d.ts +0 -15
  123. package/build/typescript/request-router.d.ts.map +0 -1
  124. package/build/typescript/shared/source-code.d.ts +0 -5
  125. package/build/typescript/shared/source-code.d.ts.map +0 -1
  126. package/quilt.project.ts +0 -5
package/build/esm/app.mjs CHANGED
@@ -1,13 +1,66 @@
1
1
  import * as path from 'node:path';
2
2
  import * as fs from 'node:fs/promises';
3
3
  import { glob } from 'glob';
4
- import { fileURLToPath } from 'node:url';
4
+ import { createRequire } from 'node:module';
5
5
  import { MAGIC_MODULE_ENTRY, MAGIC_MODULE_APP_COMPONENT, MAGIC_MODULE_REQUEST_ROUTER, MAGIC_MODULE_BROWSER_ASSETS } from './constants.mjs';
6
+ import { resolveEnvOption } from './features/env.mjs';
6
7
  import { multiline } from './shared/strings.mjs';
7
8
  import { getNodePlugins, removeBuildFiles } from './shared/rollup.mjs';
8
9
  import { createMagicModulePlugin } from './shared/magic-module.mjs';
9
- import { getBrowserTargetDetails } from './shared/browserslist.mjs';
10
+ import { getBrowserGroups, getBrowserGroupTargetDetails, targetsSupportModules, rollupGenerateOptionsForBrowsers, getBrowserGroupRegularExpressions } from './shared/browserslist.mjs';
11
+ import { loadPackageJSON } from './shared/package-json.mjs';
12
+ import { resolveRoot } from './shared/path.mjs';
10
13
 
14
+ const require = createRequire(import.meta.url);
15
+ async function quiltApp({
16
+ root: rootPath = process.cwd(),
17
+ app,
18
+ env,
19
+ graphql,
20
+ assets,
21
+ browser: browserOptions,
22
+ server: serverOptions
23
+ } = {}) {
24
+ const root = resolveRoot(rootPath);
25
+ const browserGroups = await getBrowserGroups({ root });
26
+ const browserGroupEntries = Object.entries(browserGroups);
27
+ const hasMultipleBrowserGroups = browserGroupEntries.length > 1;
28
+ const optionPromises = [];
29
+ browserGroupEntries.forEach(([name, browsers], index) => {
30
+ optionPromises.push(
31
+ quiltAppBrowser({
32
+ root,
33
+ app,
34
+ graphql,
35
+ ...browserOptions,
36
+ env: {
37
+ ...resolveEnvOption(env),
38
+ ...resolveEnvOption(browserOptions?.env)
39
+ },
40
+ assets: {
41
+ ...assets,
42
+ ...browserOptions?.assets,
43
+ // Only clean on the first build, otherwise each subsequent build removes
44
+ // assets from the previous ones.
45
+ clean: index === 0,
46
+ priority: index,
47
+ targets: hasMultipleBrowserGroups ? { name, browsers } : browsers
48
+ }
49
+ })
50
+ );
51
+ });
52
+ optionPromises.push(
53
+ quiltAppServer({
54
+ root,
55
+ app,
56
+ graphql,
57
+ ...serverOptions,
58
+ env: { ...resolveEnvOption(env), ...resolveEnvOption(serverOptions?.env) },
59
+ assets: { ...assets, ...serverOptions?.assets }
60
+ })
61
+ );
62
+ return Promise.all(optionPromises);
63
+ }
11
64
  async function quiltAppBrowser({
12
65
  root: rootPath = process.cwd(),
13
66
  app,
@@ -17,246 +70,306 @@ async function quiltAppBrowser({
17
70
  module,
18
71
  graphql = true
19
72
  } = {}) {
20
- const root = fileURLToPath(rootPath);
21
- const mode = (typeof env === 'object' ? env?.mode : undefined) ?? 'production';
22
- const minify = assets?.minify ?? mode === 'production';
23
- const baseURL = assets?.baseURL ?? '/assets/';
24
- const browserTarget = await getBrowserTargetDetails(assets?.targets, {
73
+ const root = resolveRoot(rootPath);
74
+ const mode = (typeof env === "object" ? env?.mode : env) ?? "production";
75
+ const minify = assets?.minify ?? mode === "production";
76
+ const baseURL = assets?.baseURL ?? "/assets/";
77
+ const assetsInline = assets?.inline ?? true;
78
+ const browserGroup = await getBrowserGroupTargetDetails(assets?.targets, {
25
79
  root
26
80
  });
27
- const targetFilenamePart = browserTarget.name ? `.${browserTarget.name}` : '';
28
- const [{
29
- visualizer
30
- }, {
31
- magicModuleEnv,
32
- replaceProcessEnv
33
- }, {
34
- sourceCode
35
- }, {
36
- createTSConfigAliasPlugin
37
- }, {
38
- css
39
- }, {
40
- assetManifest,
41
- rawAssets,
42
- staticAssets
43
- }, {
44
- systemJS
45
- }, nodePlugins] = await Promise.all([import('rollup-plugin-visualizer'), import('./features/env.mjs'), import('./features/source-code.mjs'), import('./features/typescript.mjs'), import('./features/css.mjs'), import('./features/assets.mjs'), import('./features/system-js.mjs'), getNodePlugins()]);
46
- const plugins = [...nodePlugins, systemJS({
47
- minify
48
- }), replaceProcessEnv({
49
- mode
50
- }), magicModuleEnv({
51
- ...env,
52
- mode
53
- }), sourceCode({
54
- mode,
55
- targets: browserTarget.browsers
56
- }), css({
57
- minify,
58
- emit: true
59
- }), rawAssets(), staticAssets({
60
- baseURL,
61
- emit: true
62
- }), removeBuildFiles(['build/assets', 'build/manifests', 'build/reports'], {
63
- root
64
- })];
81
+ const targetFilenamePart = browserGroup.name ? `.${browserGroup.name}` : "";
82
+ const [
83
+ { visualizer },
84
+ { magicModuleEnv, replaceProcessEnv },
85
+ { sourceCode },
86
+ { createTSConfigAliasPlugin },
87
+ { css },
88
+ { assetManifest, rawAssets, staticAssets },
89
+ { asyncModules },
90
+ { systemJS },
91
+ { workers },
92
+ { esnext },
93
+ nodePlugins,
94
+ packageJSON
95
+ ] = await Promise.all([
96
+ import('rollup-plugin-visualizer'),
97
+ import('./features/env.mjs'),
98
+ import('./features/source-code.mjs'),
99
+ import('./features/typescript.mjs'),
100
+ import('./features/css.mjs'),
101
+ import('./features/assets.mjs'),
102
+ import('./features/async.mjs'),
103
+ import('./features/system-js.mjs'),
104
+ import('./features/workers.mjs'),
105
+ import('./features/esnext.mjs'),
106
+ getNodePlugins({ bundle: true }),
107
+ loadPackageJSON(root)
108
+ ]);
109
+ const plugins = [
110
+ ...nodePlugins,
111
+ systemJS({ minify }),
112
+ replaceProcessEnv({ mode }),
113
+ magicModuleEnv({ ...resolveEnvOption(env), mode }),
114
+ sourceCode({
115
+ mode,
116
+ targets: browserGroup.browsers,
117
+ babel: {
118
+ useBuiltIns: "entry",
119
+ options(options) {
120
+ return {
121
+ ...options,
122
+ plugins: [
123
+ ...options?.plugins ?? [],
124
+ require.resolve("@quilted/babel/async"),
125
+ require.resolve("@quilted/babel/workers")
126
+ ]
127
+ };
128
+ }
129
+ }
130
+ }),
131
+ esnext({
132
+ mode,
133
+ targets: browserGroup.browsers
134
+ }),
135
+ css({ minify, emit: true }),
136
+ rawAssets(),
137
+ staticAssets({
138
+ baseURL,
139
+ emit: true,
140
+ inlineLimit: assetsInline ? typeof assetsInline === "boolean" ? void 0 : assetsInline?.limit : Number.POSITIVE_INFINITY
141
+ }),
142
+ asyncModules({
143
+ baseURL,
144
+ preload: true,
145
+ moduleID: ({ imported }) => path.relative(root, imported)
146
+ }),
147
+ workers({
148
+ baseURL,
149
+ outputOptions: {
150
+ format: "iife",
151
+ inlineDynamicImports: true,
152
+ dir: path.resolve(root, `build/assets`),
153
+ entryFileNames: `[name]${targetFilenamePart}.[hash].js`,
154
+ assetFileNames: `[name]${targetFilenamePart}.[hash].[ext]`,
155
+ chunkFileNames: `[name]${targetFilenamePart}.[hash].js`
156
+ }
157
+ })
158
+ ];
159
+ if (assets?.clean ?? true) {
160
+ plugins.push(
161
+ removeBuildFiles(["build/assets", "build/manifests", "build/reports"], {
162
+ root
163
+ })
164
+ );
165
+ }
65
166
  const tsconfigAliases = await createTSConfigAliasPlugin();
66
167
  if (tsconfigAliases) {
67
168
  plugins.push(tsconfigAliases);
68
169
  }
69
- const appEntry = app ?? (await glob('{App,app,input}.{ts,tsx,mjs,js,jsx}', {
70
- cwd: root,
71
- nodir: true,
72
- absolute: true
73
- }).then(files => files[0]));
170
+ const appEntry = await resolveAppEntry(app, { root, packageJSON });
74
171
  if (appEntry) {
75
- plugins.push(magicModuleAppComponent({
76
- entry: appEntry
77
- }));
172
+ plugins.push(magicModuleAppComponent({ entry: appEntry }));
78
173
  }
79
174
  plugins.push(magicModuleAppBrowserEntry(module));
80
175
  if (graphql) {
81
- const {
82
- graphql
83
- } = await import('./features/graphql.mjs');
84
- plugins.push(graphql({
85
- manifest: path.resolve(`manifests/graphql${targetFilenamePart}.json`)
86
- }));
176
+ const { graphql: graphql2 } = await import('./features/graphql.mjs');
177
+ plugins.push(
178
+ graphql2({
179
+ manifest: path.resolve(`manifests/graphql${targetFilenamePart}.json`)
180
+ })
181
+ );
87
182
  }
88
183
  if (minify) {
89
- const {
90
- minify
91
- } = await import('rollup-plugin-esbuild');
92
- plugins.push(minify());
184
+ const { minify: minify2 } = await import('rollup-plugin-esbuild');
185
+ plugins.push(minify2());
186
+ }
187
+ const cacheKey = new URLSearchParams();
188
+ if (browserGroup.name) {
189
+ cacheKey.set("browserGroup", browserGroup.name);
93
190
  }
94
- const cacheKey = browserTarget.name ? {
95
- browserTarget: browserTarget.name
96
- } : undefined;
97
- const id = browserTarget.name ? browserTarget.name : undefined;
98
- plugins.push(assetManifest({
99
- id,
100
- cacheKey,
101
- baseURL,
102
- file: path.resolve(`build/manifests/assets${targetFilenamePart}.json`),
103
- priority: assets?.priority
104
- }), visualizer({
105
- template: 'treemap',
106
- open: false,
107
- brotliSize: true,
108
- filename: path.resolve(`build/reports/bundle-visualizer${targetFilenamePart}.html`)
109
- }));
110
- const finalEntry = entry ?? (await glob('{browser,client}.{ts,tsx,mjs,js,jsx}', {
191
+ plugins.push(
192
+ assetManifest({
193
+ baseURL,
194
+ cacheKey,
195
+ file: path.resolve(`build/manifests/assets${targetFilenamePart}.json`),
196
+ priority: assets?.priority
197
+ }),
198
+ visualizer({
199
+ template: "treemap",
200
+ open: false,
201
+ brotliSize: true,
202
+ filename: path.resolve(
203
+ `build/reports/bundle-visualizer${targetFilenamePart}.html`
204
+ )
205
+ })
206
+ );
207
+ const finalEntry = entry ? path.resolve(root, entry) : await glob("{browser,client,web}.{ts,tsx,mjs,js,jsx}", {
111
208
  cwd: root,
112
209
  nodir: true,
113
210
  absolute: true
114
- }).then(files => files[0])) ?? MAGIC_MODULE_ENTRY;
211
+ }).then((files) => files[0]) ?? MAGIC_MODULE_ENTRY;
212
+ const isESM = await targetsSupportModules(browserGroup.browsers);
115
213
  return {
116
214
  input: finalEntry,
117
215
  plugins,
118
216
  onwarn(warning, defaultWarn) {
119
- // Removes annoying warnings for React-focused libraries that
120
- // include 'use client' directives.
121
- if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && /['"]use client['"]/.test(warning.message)) {
217
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && /['"]use client['"]/.test(warning.message)) {
122
218
  return;
123
219
  }
124
220
  defaultWarn(warning);
125
221
  },
126
222
  output: {
127
- // format: isESM ? 'esm' : 'systemjs',
128
- format: 'esm',
129
- dir: path.resolve(`build/assets`),
223
+ format: isESM ? "esm" : "systemjs",
224
+ dir: path.resolve(root, `build/assets`),
130
225
  entryFileNames: `app${targetFilenamePart}.[hash].js`,
131
226
  assetFileNames: `[name]${targetFilenamePart}.[hash].[ext]`,
132
227
  chunkFileNames: `[name]${targetFilenamePart}.[hash].js`,
133
- manualChunks: createManualChunksSorter()
228
+ manualChunks: createManualChunksSorter(),
229
+ generatedCode: await rollupGenerateOptionsForBrowsers(
230
+ browserGroup.browsers
231
+ )
134
232
  }
135
233
  };
136
234
  }
137
235
  async function quiltAppServer({
236
+ root: rootPath = process.cwd(),
138
237
  app,
139
238
  env,
140
239
  entry,
240
+ format = "request-router",
141
241
  graphql = true,
142
- minify = false
242
+ assets,
243
+ output
143
244
  } = {}) {
144
- const root = process.cwd();
145
- const mode = (typeof env === 'object' ? env?.mode : undefined) ?? 'production';
146
- const [{
147
- visualizer
148
- }, {
149
- sourceCode
150
- }, {
151
- createTSConfigAliasPlugin
152
- }, {
153
- css
154
- }, {
155
- rawAssets,
156
- staticAssets
157
- }, {
158
- magicModuleRequestRouterEntry
159
- }, nodePlugins] = await Promise.all([import('rollup-plugin-visualizer'), import('./features/source-code.mjs'), import('./features/typescript.mjs'), import('./features/css.mjs'), import('./features/assets.mjs'), import('./features/request-router.mjs'), getNodePlugins()]);
160
- const plugins = [...nodePlugins, sourceCode({
161
- mode,
162
- targets: ['current node']
163
- }), css({
164
- emit: false,
165
- minify
166
- }), rawAssets(), staticAssets({
167
- emit: false
168
- }), removeBuildFiles(['build/server'], {
169
- root
170
- })];
245
+ const root = resolveRoot(rootPath);
246
+ const mode = (typeof env === "object" ? env?.mode : env) ?? "production";
247
+ const baseURL = assets?.baseURL ?? "/assets/";
248
+ const assetsInline = assets?.inline ?? true;
249
+ const bundle = output?.bundle;
250
+ const minify = output?.minify ?? false;
251
+ const hash = output?.hash ?? "async-only";
252
+ const outputFormat = output?.format ?? "esmodules";
253
+ const [
254
+ { visualizer },
255
+ { magicModuleEnv, replaceProcessEnv },
256
+ { sourceCode },
257
+ { createTSConfigAliasPlugin },
258
+ { css },
259
+ { rawAssets, staticAssets },
260
+ { asyncModules },
261
+ { esnext },
262
+ nodePlugins,
263
+ packageJSON
264
+ ] = await Promise.all([
265
+ import('rollup-plugin-visualizer'),
266
+ import('./features/env.mjs'),
267
+ import('./features/source-code.mjs'),
268
+ import('./features/typescript.mjs'),
269
+ import('./features/css.mjs'),
270
+ import('./features/assets.mjs'),
271
+ import('./features/async.mjs'),
272
+ import('./features/esnext.mjs'),
273
+ getNodePlugins({ bundle }),
274
+ loadPackageJSON(root)
275
+ ]);
276
+ const plugins = [
277
+ ...nodePlugins,
278
+ replaceProcessEnv({ mode }),
279
+ magicModuleEnv({ ...resolveEnvOption(env), mode }),
280
+ sourceCode({
281
+ mode,
282
+ targets: ["current node"],
283
+ babel: {
284
+ options(options) {
285
+ return {
286
+ ...options,
287
+ plugins: [
288
+ ...options?.plugins ?? [],
289
+ require.resolve("@quilted/babel/async"),
290
+ [require.resolve("@quilted/babel/workers"), { noop: true }]
291
+ ]
292
+ };
293
+ }
294
+ }
295
+ }),
296
+ esnext({
297
+ mode,
298
+ targets: ["current node"]
299
+ }),
300
+ css({ emit: false, minify }),
301
+ rawAssets(),
302
+ staticAssets({
303
+ emit: false,
304
+ baseURL,
305
+ inlineLimit: assetsInline ? typeof assetsInline === "boolean" ? void 0 : assetsInline?.limit : Number.POSITIVE_INFINITY
306
+ }),
307
+ asyncModules({
308
+ baseURL,
309
+ preload: false,
310
+ moduleID: ({ imported }) => path.relative(root, imported)
311
+ }),
312
+ removeBuildFiles(["build/server"], { root })
313
+ ];
171
314
  const tsconfigAliases = await createTSConfigAliasPlugin();
172
315
  if (tsconfigAliases) {
173
316
  plugins.push(tsconfigAliases);
174
317
  }
175
- if (env) {
176
- const {
177
- magicModuleEnv,
178
- replaceProcessEnv
179
- } = await import('./features/env.mjs');
180
- if (typeof env === 'boolean') {
181
- plugins.push(replaceProcessEnv({
182
- mode
183
- }));
184
- plugins.push(magicModuleEnv({
185
- mode
186
- }));
187
- } else {
188
- plugins.push(replaceProcessEnv({
189
- mode
190
- }));
191
- plugins.push(magicModuleEnv({
192
- mode
193
- }));
194
- }
318
+ const appEntry = await resolveAppEntry(app, { root, packageJSON });
319
+ if (appEntry) {
320
+ plugins.push(magicModuleAppComponent({ entry: appEntry }));
195
321
  }
196
- const appEntry = app ?? (await glob('{App,app,input}.{ts,tsx,mjs,js,jsx}', {
322
+ const serverEntry = entry ? path.resolve(root, entry) : await glob("{server,service,backend}.{ts,tsx,mjs,js,jsx}", {
197
323
  cwd: root,
198
324
  nodir: true,
199
325
  absolute: true
200
- }).then(files => files[0]));
201
- if (appEntry) {
202
- plugins.push(magicModuleAppComponent({
203
- entry: appEntry
204
- }));
205
- }
206
- plugins.push(magicModuleRequestRouterEntry());
207
- plugins.push(magicModuleAppRequestRouter({
208
- entry
209
- }));
210
- plugins.push(magicModuleAppAssetManifests());
326
+ }).then((files) => files[0]);
327
+ const finalEntry = format === "request-router" ? MAGIC_MODULE_ENTRY : serverEntry ?? MAGIC_MODULE_ENTRY;
328
+ plugins.push(
329
+ magicModuleAppServerEntry({
330
+ assets: { baseURL }
331
+ }),
332
+ magicModuleAppRequestRouter({ entry: serverEntry }),
333
+ magicModuleAppAssetManifests()
334
+ );
211
335
  if (graphql) {
212
- const {
213
- graphql
214
- } = await import('./features/graphql.mjs');
215
- plugins.push(graphql({
216
- manifest: false
217
- }));
336
+ const { graphql: graphql2 } = await import('./features/graphql.mjs');
337
+ plugins.push(graphql2({ manifest: false }));
218
338
  }
219
339
  if (minify) {
220
- const {
221
- minify
222
- } = await import('rollup-plugin-esbuild');
223
- plugins.push(minify());
340
+ const { minify: minify2 } = await import('rollup-plugin-esbuild');
341
+ plugins.push(minify2());
224
342
  }
225
- plugins.push(visualizer({
226
- template: 'treemap',
227
- open: false,
228
- brotliSize: false,
229
- filename: path.resolve(`build/reports/bundle-visualizer.server.html`)
230
- }));
231
- const finalEntry = entry ?? (await glob('{server,service,backend}.{ts,tsx,mjs,js,jsx}', {
232
- cwd: root,
233
- nodir: true,
234
- absolute: true
235
- }).then(files => files[0])) ?? MAGIC_MODULE_ENTRY;
343
+ plugins.push(
344
+ visualizer({
345
+ template: "treemap",
346
+ open: false,
347
+ brotliSize: false,
348
+ filename: path.resolve(`build/reports/bundle-visualizer.server.html`)
349
+ })
350
+ );
236
351
  return {
237
352
  input: finalEntry,
238
353
  plugins,
239
354
  onwarn(warning, defaultWarn) {
240
- // Removes annoying warnings for React-focused libraries that
241
- // include 'use client' directives.
242
- if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && /['"]use client['"]/.test(warning.message)) {
355
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && /['"]use client['"]/.test(warning.message)) {
243
356
  return;
244
357
  }
245
358
  defaultWarn(warning);
246
359
  },
247
360
  output: {
248
- // format: isESM ? 'esm' : 'systemjs',
249
- format: 'esm',
361
+ format: outputFormat === "commonjs" || outputFormat === "cjs" ? "cjs" : "esm",
250
362
  dir: path.resolve(`build/server`),
251
- entryFileNames: 'server.js'
363
+ entryFileNames: `server${hash === true ? `.[hash]` : ""}.js`,
364
+ chunkFileNames: `[name]${hash === true || hash === "async-only" ? `.[hash]` : ""}.js`,
365
+ assetFileNames: `[name]${hash === true ? `.[hash]` : ""}.[ext]`,
366
+ generatedCode: "es2015"
252
367
  }
253
368
  };
254
369
  }
255
- function magicModuleAppComponent({
256
- entry
257
- }) {
370
+ function magicModuleAppComponent({ entry }) {
258
371
  return createMagicModulePlugin({
259
- name: '@quilted/magic-module/app',
372
+ name: "@quilted/magic-module/app",
260
373
  module: MAGIC_MODULE_APP_COMPONENT,
261
374
  alias: entry
262
375
  });
@@ -265,10 +378,10 @@ function magicModuleAppRequestRouter({
265
378
  entry
266
379
  } = {}) {
267
380
  return createMagicModulePlugin({
268
- name: '@quilted/magic-module/app-request-router',
381
+ name: "@quilted/magic-module/app-request-router",
269
382
  module: MAGIC_MODULE_REQUEST_ROUTER,
270
383
  alias: entry,
271
- source: entry ? undefined : async function source() {
384
+ source: entry ? void 0 : async function source() {
272
385
  return multiline`
273
386
  import '@quilted/quilt/globals';
274
387
 
@@ -277,7 +390,9 @@ function magicModuleAppRequestRouter({
277
390
  import {renderToResponse} from '@quilted/quilt/server';
278
391
 
279
392
  import App from ${JSON.stringify(MAGIC_MODULE_APP_COMPONENT)};
280
- import {BrowserAssets} from ${JSON.stringify(MAGIC_MODULE_BROWSER_ASSETS)};
393
+ import {BrowserAssets} from ${JSON.stringify(
394
+ MAGIC_MODULE_BROWSER_ASSETS
395
+ )};
281
396
 
282
397
  const router = new RequestRouter();
283
398
  const assets = new BrowserAssets();
@@ -299,14 +414,14 @@ function magicModuleAppRequestRouter({
299
414
  }
300
415
  function magicModuleAppBrowserEntry({
301
416
  hydrate = true,
302
- selector = '#app'
417
+ selector = "#app"
303
418
  } = {}) {
304
419
  return createMagicModulePlugin({
305
- name: '@quilted/magic-module/app-browser-entry',
420
+ name: "@quilted/magic-module/app-browser-entry",
306
421
  module: MAGIC_MODULE_ENTRY,
307
422
  sideEffects: true,
308
423
  async source() {
309
- const reactRootFunction = hydrate ? 'hydrateRoot' : 'createRoot';
424
+ const reactRootFunction = hydrate ? "hydrateRoot" : "createRoot";
310
425
  return multiline`
311
426
  import '@quilted/quilt/globals';
312
427
 
@@ -322,27 +437,86 @@ function magicModuleAppBrowserEntry({
322
437
  }
323
438
  });
324
439
  }
440
+ function magicModuleAppServerEntry({
441
+ host,
442
+ port,
443
+ assets,
444
+ format = "module"
445
+ } = {}) {
446
+ const baseURL = typeof assets === "object" ? assets.baseURL : "/assets/";
447
+ return createMagicModulePlugin({
448
+ name: "@quilted/request-router/app-server",
449
+ module: MAGIC_MODULE_ENTRY,
450
+ sideEffects: true,
451
+ async source() {
452
+ const serveAssets = Boolean(assets);
453
+ return multiline`
454
+ ${serveAssets ? `import * as path from 'path';` : ""}
455
+ ${serveAssets && format === "module" ? `import {fileURLToPath} from 'url';` : ""}
456
+ import {createServer} from 'http';
457
+
458
+ import requestRouter from ${JSON.stringify(
459
+ MAGIC_MODULE_REQUEST_ROUTER
460
+ )};
461
+
462
+ import {createHttpRequestListener${serveAssets ? ", serveStatic" : ""}} from '@quilted/quilt/request-router/node';
463
+
464
+ const port = ${port ?? "Number.parseInt(process.env.PORT, 10)"};
465
+ const host = ${host ? JSON.stringify(host) : "process.env.HOST"};
466
+
467
+ ${serveAssets ? `const dirname = ${format === "module" ? "path.dirname(fileURLToPath(import.meta.url))" : "__dirname"};
468
+ const serve = serveStatic(path.resolve(dirname, '../assets'), {
469
+ baseUrl: ${JSON.stringify(baseURL)},
470
+ });` : ""}
471
+ const listener = createHttpRequestListener(requestRouter);
472
+
473
+ createServer(async (request, response) => {
474
+ ${serveAssets ? `if (request.url.startsWith(${JSON.stringify(
475
+ baseURL
476
+ )})) return serve(request, response);` : ""}
477
+
478
+ await listener(request, response);
479
+ }).listen(port, host);
480
+ `;
481
+ }
482
+ });
483
+ }
325
484
  function magicModuleAppAssetManifests() {
326
485
  return createMagicModulePlugin({
327
- name: '@quilted/magic-module/asset-manifests',
486
+ name: "@quilted/magic-module/asset-manifests",
328
487
  module: MAGIC_MODULE_BROWSER_ASSETS,
329
488
  async source() {
330
- const {
331
- glob
332
- } = await import('glob');
333
- const manifestFiles = await glob('assets*.json', {
489
+ const { glob: glob2 } = await import('glob');
490
+ const manifestFiles = await glob2("assets*.json", {
334
491
  nodir: true,
335
492
  absolute: true,
336
493
  cwd: path.resolve(`build/manifests`)
337
494
  });
338
- const manifests = await Promise.all(manifestFiles.map(async file => JSON.parse(await fs.readFile(file, 'utf8'))));
339
- manifests.sort((manifestA, manifestB) => (manifestA.priority ?? 0) - (manifestB.priority ?? 0));
495
+ const manifests = await Promise.all(
496
+ manifestFiles.map(
497
+ async (file) => JSON.parse(await fs.readFile(file, "utf8"))
498
+ )
499
+ );
500
+ manifests.sort(
501
+ (manifestA, manifestB) => (manifestA.priority ?? 0) - (manifestB.priority ?? 0)
502
+ );
503
+ const browserGroupRegexes = await getBrowserGroupRegularExpressions();
340
504
  return multiline`
341
505
  import {BrowserAssetsFromManifests} from '@quilted/quilt/server';
342
506
 
343
507
  export class BrowserAssets extends BrowserAssetsFromManifests {
344
508
  constructor() {
345
- const manifests = JSON.parse(${JSON.stringify(JSON.stringify(manifests))});
509
+ const manifests = JSON.parse(${JSON.stringify(
510
+ JSON.stringify(manifests)
511
+ )});
512
+
513
+ const browserGroupTests = [
514
+ ${Object.entries(browserGroupRegexes).map(
515
+ ([name, test]) => `[${JSON.stringify(name)}, new RegExp(${JSON.stringify(
516
+ test.source
517
+ )})]`
518
+ ).join(", ")}
519
+ ];
346
520
 
347
521
  // The default manifest is the last one, since it has the widest browser support.
348
522
  const defaultManifest = manifests.at(-1);
@@ -350,6 +524,14 @@ function magicModuleAppAssetManifests() {
350
524
  super(manifests, {
351
525
  defaultManifest,
352
526
  cacheKey(request) {
527
+ const userAgent = request.headers.get('User-Agent');
528
+
529
+ if (userAgent) {
530
+ for (const [name, test] of browserGroupTests) {
531
+ if (test.test(userAgent)) return {browserGroup: name};
532
+ }
533
+ }
534
+
353
535
  return {};
354
536
  },
355
537
  });
@@ -359,71 +541,98 @@ function magicModuleAppAssetManifests() {
359
541
  }
360
542
  });
361
543
  }
362
- const FRAMEWORK_CHUNK_NAME = 'framework';
363
- const POLYFILLS_CHUNK_NAME = 'polyfills';
364
- const VENDOR_CHUNK_NAME = 'vendor';
365
- const INTERNALS_CHUNK_NAME = 'internals';
366
- const SHARED_CHUNK_NAME = 'shared';
367
- const PACKAGES_CHUNK_NAME = 'packages';
368
- const GLOBAL_CHUNK_NAME = 'global';
369
- const FRAMEWORK_TEST_STRINGS = ['/node_modules/preact/', '/node_modules/react/', '/node_modules/js-cookie/', '/node_modules/@quilted/quilt/', '/node_modules/@preact/signals/', '/node_modules/@preact/signals-core/',
370
- // TODO I should turn this into an allowlist
371
- /node_modules[/]@quilted[/](?!react-query|swr)/];
372
- const POLYFILL_TEST_STRINGS = ['/node_modules/@quilted/polyfills/', '/node_modules/core-js/', '/node_modules/whatwg-fetch/', '/node_modules/regenerator-runtime/', '/node_modules/abort-controller/'];
373
- const INTERNALS_TEST_STRINGS = ['\x00commonjsHelpers.js', '/node_modules/@babel/runtime/'];
374
-
375
- // When building from source, quilt packages are not in node_modules,
376
- // so we instead add their repo paths to the list of framework test strings.
544
+ const FRAMEWORK_CHUNK_NAME = "framework";
545
+ const POLYFILLS_CHUNK_NAME = "polyfills";
546
+ const VENDOR_CHUNK_NAME = "vendor";
547
+ const INTERNALS_CHUNK_NAME = "internals";
548
+ const SHARED_CHUNK_NAME = "shared";
549
+ const PACKAGES_CHUNK_NAME = "packages";
550
+ const GLOBAL_CHUNK_NAME = "global";
551
+ const FRAMEWORK_TEST_STRINGS = [
552
+ "/node_modules/preact/",
553
+ "/node_modules/react/",
554
+ "/node_modules/js-cookie/",
555
+ "/node_modules/@quilted/quilt/",
556
+ "/node_modules/@preact/signals/",
557
+ "/node_modules/@preact/signals-core/",
558
+ // TODO I should turn this into an allowlist
559
+ /node_modules[/]@quilted[/](?!react-query|swr)/
560
+ ];
561
+ const POLYFILL_TEST_STRINGS = [
562
+ "/node_modules/core-js/",
563
+ "/node_modules/whatwg-fetch/",
564
+ "/node_modules/regenerator-runtime/",
565
+ "/node_modules/abort-controller/"
566
+ ];
567
+ const INTERNALS_TEST_STRINGS = [
568
+ "\0commonjsHelpers.js",
569
+ "/node_modules/@babel/runtime/"
570
+ ];
377
571
  if (process.env.QUILT_FROM_SOURCE) {
378
- FRAMEWORK_TEST_STRINGS.push('/quilt/packages/');
572
+ FRAMEWORK_TEST_STRINGS.push("/quilt/packages/");
379
573
  }
380
-
381
- // Inspired by Vite: https://github.com/vitejs/vite/blob/c69f83615292953d40f07b1178d1ed1d72abe695/packages/vite/source/node/build.ts#L567
382
574
  function createManualChunksSorter() {
383
- // TODO: make this more configurable, and make it so that we bundle more intelligently
384
- // for split entries
385
- const packagesPath = path.resolve('packages') + path.sep;
386
- const globalPath = path.resolve('global') + path.sep;
387
- const sharedPath = path.resolve('shared') + path.sep;
388
- return (id, {
389
- getModuleInfo
390
- }) => {
391
- if (INTERNALS_TEST_STRINGS.some(test => id.includes(test))) {
575
+ const packagesPath = path.resolve("packages") + path.sep;
576
+ const globalPath = path.resolve("global") + path.sep;
577
+ const sharedPath = path.resolve("shared") + path.sep;
578
+ return (id, { getModuleInfo }) => {
579
+ if (INTERNALS_TEST_STRINGS.some((test) => id.includes(test))) {
392
580
  return INTERNALS_CHUNK_NAME;
393
581
  }
394
- if (FRAMEWORK_TEST_STRINGS.some(test => typeof test === 'string' ? id.includes(test) : test.test(id))) {
582
+ if (FRAMEWORK_TEST_STRINGS.some(
583
+ (test) => typeof test === "string" ? id.includes(test) : test.test(id)
584
+ )) {
395
585
  return FRAMEWORK_CHUNK_NAME;
396
586
  }
397
- if (POLYFILL_TEST_STRINGS.some(test => id.includes(test))) {
587
+ if (POLYFILL_TEST_STRINGS.some((test) => id.includes(test))) {
398
588
  return POLYFILLS_CHUNK_NAME;
399
589
  }
400
590
  let bundleBaseName;
401
591
  let relativeId;
402
- if (id.includes('/node_modules/')) {
592
+ if (id.includes("/node_modules/")) {
403
593
  const moduleInfo = getModuleInfo(id);
404
-
405
- // If the only dependency is another vendor, let Rollup handle the naming
406
- if (moduleInfo == null) return;
407
- if (moduleInfo.importers.length > 0 && moduleInfo.importers.every(importer => importer.includes('/node_modules/'))) {
594
+ if (moduleInfo == null)
595
+ return;
596
+ if (moduleInfo.importers.length > 0 && moduleInfo.importers.every(
597
+ (importer) => importer.includes("/node_modules/")
598
+ )) {
408
599
  return;
409
600
  }
410
601
  bundleBaseName = VENDOR_CHUNK_NAME;
411
- relativeId = id.replace(/^.*[/]node_modules[/]/, '');
602
+ relativeId = id.replace(/^.*[/]node_modules[/]/, "");
412
603
  } else if (id.startsWith(packagesPath)) {
413
604
  bundleBaseName = PACKAGES_CHUNK_NAME;
414
- relativeId = id.replace(packagesPath, '');
605
+ relativeId = id.replace(packagesPath, "");
415
606
  } else if (id.startsWith(globalPath)) {
416
607
  bundleBaseName = GLOBAL_CHUNK_NAME;
417
- relativeId = id.replace(globalPath, '');
608
+ relativeId = id.replace(globalPath, "");
418
609
  } else if (id.startsWith(sharedPath)) {
419
610
  bundleBaseName = SHARED_CHUNK_NAME;
420
- relativeId = id.replace(sharedPath, '');
611
+ relativeId = id.replace(sharedPath, "");
421
612
  }
422
613
  if (bundleBaseName == null || relativeId == null) {
423
614
  return;
424
615
  }
425
- return `${bundleBaseName}-${relativeId.split(path.sep)[0]?.split('.')[0]}`;
616
+ return `${bundleBaseName}-${relativeId.split(path.sep)[0]?.split(".")[0]}`;
426
617
  };
427
618
  }
619
+ async function resolveAppEntry(entry, { root, packageJSON }) {
620
+ if (entry) {
621
+ return path.resolve(root, entry);
622
+ }
623
+ if (typeof packageJSON.main === "string") {
624
+ return path.resolve(root, packageJSON.main);
625
+ }
626
+ const rootEntry = packageJSON.exports?.["."];
627
+ if (typeof rootEntry === "string") {
628
+ return path.resolve(root, rootEntry);
629
+ }
630
+ const globbed = await glob("{App,app,index}.{ts,tsx,mjs,js,jsx}", {
631
+ cwd: root,
632
+ nodir: true,
633
+ absolute: true
634
+ });
635
+ return globbed[0];
636
+ }
428
637
 
429
- export { magicModuleAppAssetManifests, magicModuleAppBrowserEntry, magicModuleAppComponent, magicModuleAppRequestRouter, quiltAppBrowser, quiltAppServer };
638
+ export { magicModuleAppAssetManifests, magicModuleAppBrowserEntry, magicModuleAppComponent, magicModuleAppRequestRouter, magicModuleAppServerEntry, quiltApp, quiltAppBrowser, quiltAppServer };