@quilted/rollup 0.1.19 → 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 +19 -0
  2. package/build/esm/app.mjs +443 -219
  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 +466 -96
  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 -441
  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 -414
  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,231 +70,306 @@ async function quiltAppBrowser({
17
70
  module,
18
71
  graphql = true
19
72
  } = {}) {
20
- const root = typeof rootPath === 'string' ? rootPath : 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
- magicModuleEnv,
150
- replaceProcessEnv
151
- }, {
152
- sourceCode
153
- }, {
154
- createTSConfigAliasPlugin
155
- }, {
156
- css
157
- }, {
158
- rawAssets,
159
- staticAssets
160
- }, {
161
- magicModuleRequestRouterEntry
162
- }, 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/request-router.mjs'), getNodePlugins()]);
163
- const plugins = [...nodePlugins, replaceProcessEnv({
164
- mode
165
- }), magicModuleEnv({
166
- ...env,
167
- mode
168
- }), sourceCode({
169
- mode,
170
- targets: ['current node']
171
- }), css({
172
- emit: false,
173
- minify
174
- }), rawAssets(), staticAssets({
175
- emit: false
176
- }), removeBuildFiles(['build/server'], {
177
- root
178
- })];
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
+ ];
179
314
  const tsconfigAliases = await createTSConfigAliasPlugin();
180
315
  if (tsconfigAliases) {
181
316
  plugins.push(tsconfigAliases);
182
317
  }
183
- const appEntry = app ?? (await glob('{App,app,input}.{ts,tsx,mjs,js,jsx}', {
318
+ const appEntry = await resolveAppEntry(app, { root, packageJSON });
319
+ if (appEntry) {
320
+ plugins.push(magicModuleAppComponent({ entry: appEntry }));
321
+ }
322
+ const serverEntry = entry ? path.resolve(root, entry) : await glob("{server,service,backend}.{ts,tsx,mjs,js,jsx}", {
184
323
  cwd: root,
185
324
  nodir: true,
186
325
  absolute: true
187
- }).then(files => files[0]));
188
- if (appEntry) {
189
- plugins.push(magicModuleAppComponent({
190
- entry: appEntry
191
- }));
192
- }
193
- plugins.push(magicModuleRequestRouterEntry(), magicModuleAppRequestRouter({
194
- entry
195
- }), 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
+ );
196
335
  if (graphql) {
197
- const {
198
- graphql
199
- } = await import('./features/graphql.mjs');
200
- plugins.push(graphql({
201
- manifest: false
202
- }));
336
+ const { graphql: graphql2 } = await import('./features/graphql.mjs');
337
+ plugins.push(graphql2({ manifest: false }));
203
338
  }
204
339
  if (minify) {
205
- const {
206
- minify
207
- } = await import('rollup-plugin-esbuild');
208
- plugins.push(minify());
340
+ const { minify: minify2 } = await import('rollup-plugin-esbuild');
341
+ plugins.push(minify2());
209
342
  }
210
- plugins.push(visualizer({
211
- template: 'treemap',
212
- open: false,
213
- brotliSize: false,
214
- filename: path.resolve(`build/reports/bundle-visualizer.server.html`)
215
- }));
216
- const finalEntry = entry ?? (await glob('{server,service,backend}.{ts,tsx,mjs,js,jsx}', {
217
- cwd: root,
218
- nodir: true,
219
- absolute: true
220
- }).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
+ );
221
351
  return {
222
352
  input: finalEntry,
223
353
  plugins,
224
354
  onwarn(warning, defaultWarn) {
225
- // Removes annoying warnings for React-focused libraries that
226
- // include 'use client' directives.
227
- if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && /['"]use client['"]/.test(warning.message)) {
355
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && /['"]use client['"]/.test(warning.message)) {
228
356
  return;
229
357
  }
230
358
  defaultWarn(warning);
231
359
  },
232
360
  output: {
233
- // format: isESM ? 'esm' : 'systemjs',
234
- format: 'esm',
361
+ format: outputFormat === "commonjs" || outputFormat === "cjs" ? "cjs" : "esm",
235
362
  dir: path.resolve(`build/server`),
236
- 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"
237
367
  }
238
368
  };
239
369
  }
240
- function magicModuleAppComponent({
241
- entry
242
- }) {
370
+ function magicModuleAppComponent({ entry }) {
243
371
  return createMagicModulePlugin({
244
- name: '@quilted/magic-module/app',
372
+ name: "@quilted/magic-module/app",
245
373
  module: MAGIC_MODULE_APP_COMPONENT,
246
374
  alias: entry
247
375
  });
@@ -250,10 +378,10 @@ function magicModuleAppRequestRouter({
250
378
  entry
251
379
  } = {}) {
252
380
  return createMagicModulePlugin({
253
- name: '@quilted/magic-module/app-request-router',
381
+ name: "@quilted/magic-module/app-request-router",
254
382
  module: MAGIC_MODULE_REQUEST_ROUTER,
255
383
  alias: entry,
256
- source: entry ? undefined : async function source() {
384
+ source: entry ? void 0 : async function source() {
257
385
  return multiline`
258
386
  import '@quilted/quilt/globals';
259
387
 
@@ -262,7 +390,9 @@ function magicModuleAppRequestRouter({
262
390
  import {renderToResponse} from '@quilted/quilt/server';
263
391
 
264
392
  import App from ${JSON.stringify(MAGIC_MODULE_APP_COMPONENT)};
265
- import {BrowserAssets} from ${JSON.stringify(MAGIC_MODULE_BROWSER_ASSETS)};
393
+ import {BrowserAssets} from ${JSON.stringify(
394
+ MAGIC_MODULE_BROWSER_ASSETS
395
+ )};
266
396
 
267
397
  const router = new RequestRouter();
268
398
  const assets = new BrowserAssets();
@@ -284,14 +414,14 @@ function magicModuleAppRequestRouter({
284
414
  }
285
415
  function magicModuleAppBrowserEntry({
286
416
  hydrate = true,
287
- selector = '#app'
417
+ selector = "#app"
288
418
  } = {}) {
289
419
  return createMagicModulePlugin({
290
- name: '@quilted/magic-module/app-browser-entry',
420
+ name: "@quilted/magic-module/app-browser-entry",
291
421
  module: MAGIC_MODULE_ENTRY,
292
422
  sideEffects: true,
293
423
  async source() {
294
- const reactRootFunction = hydrate ? 'hydrateRoot' : 'createRoot';
424
+ const reactRootFunction = hydrate ? "hydrateRoot" : "createRoot";
295
425
  return multiline`
296
426
  import '@quilted/quilt/globals';
297
427
 
@@ -307,27 +437,86 @@ function magicModuleAppBrowserEntry({
307
437
  }
308
438
  });
309
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
+ }
310
484
  function magicModuleAppAssetManifests() {
311
485
  return createMagicModulePlugin({
312
- name: '@quilted/magic-module/asset-manifests',
486
+ name: "@quilted/magic-module/asset-manifests",
313
487
  module: MAGIC_MODULE_BROWSER_ASSETS,
314
488
  async source() {
315
- const {
316
- glob
317
- } = await import('glob');
318
- const manifestFiles = await glob('assets*.json', {
489
+ const { glob: glob2 } = await import('glob');
490
+ const manifestFiles = await glob2("assets*.json", {
319
491
  nodir: true,
320
492
  absolute: true,
321
493
  cwd: path.resolve(`build/manifests`)
322
494
  });
323
- const manifests = await Promise.all(manifestFiles.map(async file => JSON.parse(await fs.readFile(file, 'utf8'))));
324
- 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();
325
504
  return multiline`
326
505
  import {BrowserAssetsFromManifests} from '@quilted/quilt/server';
327
506
 
328
507
  export class BrowserAssets extends BrowserAssetsFromManifests {
329
508
  constructor() {
330
- 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
+ ];
331
520
 
332
521
  // The default manifest is the last one, since it has the widest browser support.
333
522
  const defaultManifest = manifests.at(-1);
@@ -335,6 +524,14 @@ function magicModuleAppAssetManifests() {
335
524
  super(manifests, {
336
525
  defaultManifest,
337
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
+
338
535
  return {};
339
536
  },
340
537
  });
@@ -344,71 +541,98 @@ function magicModuleAppAssetManifests() {
344
541
  }
345
542
  });
346
543
  }
347
- const FRAMEWORK_CHUNK_NAME = 'framework';
348
- const POLYFILLS_CHUNK_NAME = 'polyfills';
349
- const VENDOR_CHUNK_NAME = 'vendor';
350
- const INTERNALS_CHUNK_NAME = 'internals';
351
- const SHARED_CHUNK_NAME = 'shared';
352
- const PACKAGES_CHUNK_NAME = 'packages';
353
- const GLOBAL_CHUNK_NAME = 'global';
354
- 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/',
355
- // TODO I should turn this into an allowlist
356
- /node_modules[/]@quilted[/](?!react-query|swr)/];
357
- const POLYFILL_TEST_STRINGS = ['/node_modules/@quilted/polyfills/', '/node_modules/core-js/', '/node_modules/whatwg-fetch/', '/node_modules/regenerator-runtime/', '/node_modules/abort-controller/'];
358
- const INTERNALS_TEST_STRINGS = ['\x00commonjsHelpers.js', '/node_modules/@babel/runtime/'];
359
-
360
- // When building from source, quilt packages are not in node_modules,
361
- // 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
+ ];
362
571
  if (process.env.QUILT_FROM_SOURCE) {
363
- FRAMEWORK_TEST_STRINGS.push('/quilt/packages/');
572
+ FRAMEWORK_TEST_STRINGS.push("/quilt/packages/");
364
573
  }
365
-
366
- // Inspired by Vite: https://github.com/vitejs/vite/blob/c69f83615292953d40f07b1178d1ed1d72abe695/packages/vite/source/node/build.ts#L567
367
574
  function createManualChunksSorter() {
368
- // TODO: make this more configurable, and make it so that we bundle more intelligently
369
- // for split entries
370
- const packagesPath = path.resolve('packages') + path.sep;
371
- const globalPath = path.resolve('global') + path.sep;
372
- const sharedPath = path.resolve('shared') + path.sep;
373
- return (id, {
374
- getModuleInfo
375
- }) => {
376
- 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))) {
377
580
  return INTERNALS_CHUNK_NAME;
378
581
  }
379
- 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
+ )) {
380
585
  return FRAMEWORK_CHUNK_NAME;
381
586
  }
382
- if (POLYFILL_TEST_STRINGS.some(test => id.includes(test))) {
587
+ if (POLYFILL_TEST_STRINGS.some((test) => id.includes(test))) {
383
588
  return POLYFILLS_CHUNK_NAME;
384
589
  }
385
590
  let bundleBaseName;
386
591
  let relativeId;
387
- if (id.includes('/node_modules/')) {
592
+ if (id.includes("/node_modules/")) {
388
593
  const moduleInfo = getModuleInfo(id);
389
-
390
- // If the only dependency is another vendor, let Rollup handle the naming
391
- if (moduleInfo == null) return;
392
- 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
+ )) {
393
599
  return;
394
600
  }
395
601
  bundleBaseName = VENDOR_CHUNK_NAME;
396
- relativeId = id.replace(/^.*[/]node_modules[/]/, '');
602
+ relativeId = id.replace(/^.*[/]node_modules[/]/, "");
397
603
  } else if (id.startsWith(packagesPath)) {
398
604
  bundleBaseName = PACKAGES_CHUNK_NAME;
399
- relativeId = id.replace(packagesPath, '');
605
+ relativeId = id.replace(packagesPath, "");
400
606
  } else if (id.startsWith(globalPath)) {
401
607
  bundleBaseName = GLOBAL_CHUNK_NAME;
402
- relativeId = id.replace(globalPath, '');
608
+ relativeId = id.replace(globalPath, "");
403
609
  } else if (id.startsWith(sharedPath)) {
404
610
  bundleBaseName = SHARED_CHUNK_NAME;
405
- relativeId = id.replace(sharedPath, '');
611
+ relativeId = id.replace(sharedPath, "");
406
612
  }
407
613
  if (bundleBaseName == null || relativeId == null) {
408
614
  return;
409
615
  }
410
- return `${bundleBaseName}-${relativeId.split(path.sep)[0]?.split('.')[0]}`;
616
+ return `${bundleBaseName}-${relativeId.split(path.sep)[0]?.split(".")[0]}`;
411
617
  };
412
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
+ }
413
637
 
414
- export { magicModuleAppAssetManifests, magicModuleAppBrowserEntry, magicModuleAppComponent, magicModuleAppRequestRouter, quiltAppBrowser, quiltAppServer };
638
+ export { magicModuleAppAssetManifests, magicModuleAppBrowserEntry, magicModuleAppComponent, magicModuleAppRequestRouter, magicModuleAppServerEntry, quiltApp, quiltAppBrowser, quiltAppServer };