@quilted/rollup 0.1.14 → 0.1.16

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 (44) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/cjs/app.cjs +21 -47
  3. package/build/cjs/features/assets.cjs +112 -2
  4. package/build/cjs/features/source-code.cjs +3 -2
  5. package/build/cjs/features/system-js.cjs +2 -1
  6. package/build/cjs/index.cjs +2 -0
  7. package/build/cjs/module.cjs +155 -0
  8. package/build/cjs/package.cjs +20 -2
  9. package/build/cjs/shared/browserslist.cjs +25 -0
  10. package/build/esm/app.mjs +21 -47
  11. package/build/esm/features/assets.mjs +112 -4
  12. package/build/esm/features/source-code.mjs +1 -1
  13. package/build/esm/index.mjs +1 -0
  14. package/build/esm/module.mjs +134 -0
  15. package/build/esm/package.mjs +20 -2
  16. package/build/esm/shared/browserslist.mjs +23 -0
  17. package/build/esnext/app.esnext +21 -47
  18. package/build/esnext/features/assets.esnext +112 -4
  19. package/build/esnext/features/source-code.esnext +1 -1
  20. package/build/esnext/index.esnext +1 -0
  21. package/build/esnext/module.esnext +134 -0
  22. package/build/esnext/package.esnext +20 -2
  23. package/build/esnext/shared/browserslist.esnext +23 -0
  24. package/build/tsconfig.tsbuildinfo +1 -1
  25. package/build/typescript/app.d.ts +4 -6
  26. package/build/typescript/app.d.ts.map +1 -1
  27. package/build/typescript/features/assets.d.ts +10 -2
  28. package/build/typescript/features/assets.d.ts.map +1 -1
  29. package/build/typescript/index.d.ts +1 -0
  30. package/build/typescript/index.d.ts.map +1 -1
  31. package/build/typescript/module.d.ts +45 -0
  32. package/build/typescript/module.d.ts.map +1 -0
  33. package/build/typescript/package.d.ts +8 -2
  34. package/build/typescript/package.d.ts.map +1 -1
  35. package/build/typescript/shared/browserslist.d.ts +11 -0
  36. package/build/typescript/shared/browserslist.d.ts.map +1 -0
  37. package/package.json +18 -5
  38. package/source/app.ts +21 -53
  39. package/source/features/assets.ts +152 -4
  40. package/source/features/source-code.ts +1 -1
  41. package/source/index.ts +1 -0
  42. package/source/module.ts +223 -0
  43. package/source/package.ts +19 -0
  44. package/source/shared/browserslist.ts +32 -0
@@ -1,8 +1,116 @@
1
1
  import * as path from 'node:path';
2
- import { readFile } from 'node:fs/promises';
2
+ import * as fs from 'node:fs/promises';
3
3
  import { createHash } from 'node:crypto';
4
4
  import * as mime from 'mrmime';
5
5
 
6
+ function assetManifest(manifestOptions) {
7
+ return {
8
+ name: '@quilted/asset-manifest',
9
+ async generateBundle(options, bundle) {
10
+ await writeManifestForBundle.call(this, bundle, manifestOptions, options);
11
+ }
12
+ };
13
+ }
14
+ async function writeManifestForBundle(bundle, {
15
+ id,
16
+ file,
17
+ baseURL,
18
+ cacheKey,
19
+ priority
20
+ }, {
21
+ format
22
+ }) {
23
+ const outputs = Object.values(bundle);
24
+ const entries = outputs.filter(output => output.type === 'chunk' && output.isEntry);
25
+ if (entries.length === 0) {
26
+ throw new Error(`Could not find any entries in your rollup bundle...`);
27
+ }
28
+
29
+ // We assume the first entry is the "main" one. There can be
30
+ // more than one because each worker script is also listed as an
31
+ // entry (though, from a separate build).
32
+ const entryChunk = entries[0];
33
+ const dependencyMap = new Map();
34
+ for (const output of outputs) {
35
+ if (output.type !== 'chunk') continue;
36
+ dependencyMap.set(output.fileName, output.imports);
37
+ }
38
+ const assets = [];
39
+ const assetIdMap = new Map();
40
+ function getAssetId(file) {
41
+ let id = assetIdMap.get(file);
42
+ if (id == null) {
43
+ assets.push(`${baseURL}${file}`);
44
+ id = assets.length - 1;
45
+ assetIdMap.set(file, id);
46
+ }
47
+ return id;
48
+ }
49
+ const manifest = {
50
+ id,
51
+ priority,
52
+ cacheKey,
53
+ assets,
54
+ attributes: format === 'es' ? {
55
+ scripts: {
56
+ type: 'module'
57
+ }
58
+ } : undefined,
59
+ entries: {
60
+ default: createAssetsEntry([...entryChunk.imports, entryChunk.fileName], {
61
+ dependencyMap,
62
+ getAssetId
63
+ })
64
+ },
65
+ modules: {}
66
+ };
67
+ for (const output of outputs) {
68
+ if (output.type !== 'chunk') continue;
69
+ const originalModuleId = output.facadeModuleId ?? output.moduleIds[output.moduleIds.length - 1];
70
+ if (originalModuleId == null) continue;
71
+
72
+ // This metadata is added by the rollup plugin for @quilted/async
73
+ const moduleId = this.getModuleInfo(originalModuleId)?.meta.quilt?.moduleId;
74
+ if (moduleId == null) continue;
75
+ manifest.modules[moduleId] = createAssetsEntry([...output.imports, output.fileName], {
76
+ dependencyMap,
77
+ getAssetId
78
+ });
79
+ }
80
+ await fs.mkdir(path.dirname(file), {
81
+ recursive: true
82
+ });
83
+ await fs.writeFile(file, JSON.stringify(manifest, null, 2));
84
+ }
85
+ function createAssetsEntry(files, {
86
+ dependencyMap,
87
+ getAssetId
88
+ }) {
89
+ const styles = [];
90
+ const scripts = [];
91
+ const allFiles = new Set();
92
+ const addFile = file => {
93
+ if (allFiles.has(file)) return;
94
+ allFiles.add(file);
95
+ for (const dependency of dependencyMap.get(file) ?? []) {
96
+ addFile(dependency);
97
+ }
98
+ };
99
+ for (const file of files) {
100
+ addFile(file);
101
+ }
102
+ for (const file of allFiles) {
103
+ if (file.endsWith('.css')) {
104
+ styles.push(getAssetId(file));
105
+ } else {
106
+ scripts.push(getAssetId(file));
107
+ }
108
+ }
109
+ return {
110
+ scripts,
111
+ styles
112
+ };
113
+ }
6
114
  const QUERY_PATTERN = /\?.*$/s;
7
115
  const HASH_PATTERN = /#.*$/s;
8
116
  const RAW_PATTERN = /(\?|&)raw(?:&|$)/;
@@ -26,7 +134,7 @@ function rawAssets() {
26
134
  }
27
135
  const moduleId = cleanModuleIdentifier(id);
28
136
  this.addWatchFile(moduleId);
29
- const file = await readFile(moduleId, {
137
+ const file = await fs.readFile(moduleId, {
30
138
  encoding: 'utf-8'
31
139
  });
32
140
  return `export default ${JSON.stringify(file)}`;
@@ -53,7 +161,7 @@ function staticAssets({
53
161
  return cached;
54
162
  }
55
163
  const file = cleanModuleIdentifier(id);
56
- const content = await readFile(file);
164
+ const content = await fs.readFile(file);
57
165
  let url;
58
166
  if (!file.endsWith('.svg') && content.length < inlineLimit) {
59
167
  // base64 inlined as a string
@@ -104,4 +212,4 @@ function cleanModuleIdentifier(url) {
104
212
  return url.replace(HASH_PATTERN, '').replace(QUERY_PATTERN, '');
105
213
  }
106
214
 
107
- export { rawAssets, staticAssets };
215
+ export { assetManifest, rawAssets, staticAssets };
@@ -11,7 +11,7 @@ function sourceCode({
11
11
  if (!useBabel) {
12
12
  return esbuild({
13
13
  // Support very modern features
14
- target: 'es2023',
14
+ target: 'es2022',
15
15
  jsx: 'automatic',
16
16
  jsxImportSource: 'react',
17
17
  exclude: 'node_modules/**'
@@ -1,2 +1,3 @@
1
1
  export { quiltAppBrowser, quiltAppServer } from './app.mjs';
2
+ export { quiltModule } from './module.mjs';
2
3
  export { quiltPackageESModules, quiltPackageESNext } from './package.mjs';
@@ -0,0 +1,134 @@
1
+ import * as path from 'node:path';
2
+ import { glob } from 'glob';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { getNodePlugins, removeBuildFiles } from './shared/rollup.mjs';
5
+ import { loadPackageJSON } from './shared/package-json.mjs';
6
+ import { getBrowserTargetDetails } from './shared/browserslist.mjs';
7
+
8
+ async function quiltModule({
9
+ root: rootPath = process.cwd(),
10
+ env,
11
+ assets,
12
+ graphql = true
13
+ } = {}) {
14
+ const root = typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
15
+ const mode = (typeof env === 'object' ? env?.mode : undefined) ?? 'production';
16
+ const outputDirectory = path.join(root, 'build/assets');
17
+ const minify = assets?.minify ?? true;
18
+ const hash = assets?.hash ?? true;
19
+ const hashFilenamePart = hash ? '.[hash]' : '';
20
+ const browserTarget = await getBrowserTargetDetails(assets?.targets, {
21
+ root
22
+ });
23
+ const targetFilenamePart = browserTarget.name ? `.${browserTarget.name}` : '';
24
+ const [{
25
+ visualizer
26
+ }, {
27
+ magicModuleEnv,
28
+ replaceProcessEnv
29
+ }, {
30
+ sourceCode
31
+ }, nodePlugins, packageJSON] = await Promise.all([import('rollup-plugin-visualizer'), import('./features/env.mjs'), import('./features/source-code.mjs'), getNodePlugins(), loadPackageJSON(root)]);
32
+ const source = await sourceForPackage(root, packageJSON);
33
+ const plugins = [...nodePlugins, replaceProcessEnv({
34
+ mode
35
+ }), magicModuleEnv({
36
+ ...env,
37
+ mode
38
+ }), sourceCode({
39
+ mode: 'production'
40
+ }), removeBuildFiles(['build/assets', 'build/reports'], {
41
+ root
42
+ })];
43
+ if (graphql) {
44
+ const {
45
+ graphql
46
+ } = await import('./features/graphql.mjs');
47
+ plugins.push(graphql({
48
+ manifest: false
49
+ }));
50
+ }
51
+ if (minify) {
52
+ const {
53
+ minify
54
+ } = await import('rollup-plugin-esbuild');
55
+ plugins.push(minify());
56
+ }
57
+ plugins.push(visualizer({
58
+ template: 'treemap',
59
+ open: false,
60
+ brotliSize: true,
61
+ filename: path.resolve(root, `build/reports/bundle-visualizer${targetFilenamePart}.html`)
62
+ }));
63
+ return {
64
+ input: source.files,
65
+ plugins,
66
+ onwarn(warning, defaultWarn) {
67
+ // Removes annoying warnings for React-focused libraries that
68
+ // include 'use client' directives.
69
+ if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && /['"]use client['"]/.test(warning.message)) {
70
+ return;
71
+ }
72
+ defaultWarn(warning);
73
+ },
74
+ output: {
75
+ format: 'esm',
76
+ dir: outputDirectory,
77
+ entryFileNames: `[name]${targetFilenamePart}${hashFilenamePart}.js`,
78
+ assetFileNames: `[name]${targetFilenamePart}${hashFilenamePart}.[ext]`
79
+ }
80
+ };
81
+ }
82
+ async function sourceForPackage(root, packageJSON) {
83
+ const [entries] = await Promise.all([sourceEntriesForPackage(root, packageJSON)]);
84
+ let sourceRoot = root;
85
+ const sourceEntryFiles = Object.values(entries);
86
+ for (const entry of sourceEntryFiles) {
87
+ if (!entry.startsWith(root)) continue;
88
+ sourceRoot = path.resolve(root, path.relative(root, entry).split(path.sep)[0] ?? '.');
89
+ break;
90
+ }
91
+ return {
92
+ root: sourceRoot,
93
+ files: sourceEntryFiles
94
+ };
95
+ }
96
+ async function sourceEntriesForPackage(root, packageJSON) {
97
+ const {
98
+ main,
99
+ exports
100
+ } = packageJSON;
101
+ const entries = {};
102
+ if (typeof main === 'string') {
103
+ entries['.'] = await resolveTargetFileAsSource(main, root);
104
+ }
105
+ if (typeof exports === 'string') {
106
+ entries['.'] = await resolveTargetFileAsSource(exports, root);
107
+ return entries;
108
+ } else if (exports == null || typeof exports !== 'object') {
109
+ return entries;
110
+ }
111
+ for (const [exportPath, exportCondition] of Object.entries(exports)) {
112
+ let targetFile = null;
113
+ if (exportCondition == null) continue;
114
+ if (typeof exportCondition === 'string') {
115
+ targetFile = exportCondition;
116
+ } else {
117
+ targetFile ?? (targetFile = exportCondition['source'] ?? exportCondition['quilt:source'] ?? exportCondition['quilt:esnext'] ?? Object.values(exportCondition).find(condition => typeof condition === 'string' && condition.startsWith('./build/')));
118
+ }
119
+ if (targetFile == null) continue;
120
+ const sourceFile = await resolveTargetFileAsSource(targetFile, root);
121
+ entries[exportPath] = sourceFile;
122
+ }
123
+ return entries;
124
+ }
125
+ async function resolveTargetFileAsSource(file, root) {
126
+ const sourceFile = file.includes('/build/') ? (await glob(file.replace(/[/]build[/][^/]+[/]/, '/*/').replace(/(\.d\.ts|\.[\w]+)$/, '.*'), {
127
+ cwd: root,
128
+ absolute: true,
129
+ ignore: [path.resolve(root, file)]
130
+ }))[0] : path.resolve(root, file);
131
+ return sourceFile;
132
+ }
133
+
134
+ export { quiltModule };
@@ -5,7 +5,8 @@ import { getNodePlugins, removeBuildFiles } from './shared/rollup.mjs';
5
5
  import { loadPackageJSON } from './shared/package-json.mjs';
6
6
 
7
7
  async function quiltPackageESModules({
8
- root: rootPath = process.cwd()
8
+ root: rootPath = process.cwd(),
9
+ graphql = true
9
10
  } = {}) {
10
11
  const root = typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
11
12
  const outputDirectory = path.join(root, 'build/esm');
@@ -18,6 +19,14 @@ async function quiltPackageESModules({
18
19
  }), removeBuildFiles(['build/esm'], {
19
20
  root
20
21
  })];
22
+ if (graphql) {
23
+ const {
24
+ graphql
25
+ } = await import('./features/graphql.mjs');
26
+ plugins.push(graphql({
27
+ manifest: false
28
+ }));
29
+ }
21
30
  return {
22
31
  input: source.files,
23
32
  plugins,
@@ -40,7 +49,8 @@ async function quiltPackageESModules({
40
49
  };
41
50
  }
42
51
  async function quiltPackageESNext({
43
- root: rootPath = process.cwd()
52
+ root: rootPath = process.cwd(),
53
+ graphql = true
44
54
  } = {}) {
45
55
  const root = typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
46
56
  const outputDirectory = path.join(root, 'build/esnext');
@@ -54,6 +64,14 @@ async function quiltPackageESNext({
54
64
  }), removeBuildFiles(['build/esnext'], {
55
65
  root
56
66
  })];
67
+ if (graphql) {
68
+ const {
69
+ graphql
70
+ } = await import('./features/graphql.mjs');
71
+ plugins.push(graphql({
72
+ manifest: false
73
+ }));
74
+ }
57
75
  return {
58
76
  input: source.files,
59
77
  plugins,
@@ -0,0 +1,23 @@
1
+ async function getBrowserTargetDetails(targetSelection = {}, {
2
+ root
3
+ } = {}) {
4
+ const targets = Array.isArray(targetSelection) ? {
5
+ browsers: targetSelection
6
+ } : targetSelection;
7
+ const targetBrowsers = targets.browsers ?? (await (async () => {
8
+ const {
9
+ default: browserslist
10
+ } = await import('browserslist');
11
+ const config = browserslist.findConfig(root);
12
+ if (config == null) return ['defaults'];
13
+ const targetName = targets.name ?? 'defaults';
14
+ return config[targetName] ?? ['defaults'];
15
+ })());
16
+ const name = targets.name === 'defaults' ? 'default' : targets.name;
17
+ return {
18
+ name,
19
+ browsers: targetBrowsers
20
+ };
21
+ }
22
+
23
+ export { getBrowserTargetDetails };
@@ -6,6 +6,7 @@ import { MAGIC_MODULE_ENTRY, MAGIC_MODULE_APP_COMPONENT, MAGIC_MODULE_REQUEST_RO
6
6
  import { multiline } from './shared/strings.esnext';
7
7
  import { getNodePlugins, removeBuildFiles } from './shared/rollup.esnext';
8
8
  import { createMagicModulePlugin } from './shared/magic-module.esnext';
9
+ import { getBrowserTargetDetails } from './shared/browserslist.esnext';
9
10
 
10
11
  async function quiltAppBrowser({
11
12
  root: rootPath = process.cwd(),
@@ -20,25 +21,15 @@ async function quiltAppBrowser({
20
21
  const mode = (typeof env === 'object' ? env?.mode : undefined) ?? 'production';
21
22
  const minify = assets?.minify ?? mode === 'production';
22
23
  const baseURL = assets?.baseURL ?? '/assets/';
23
- const assetTargets = assets?.targets ?? {};
24
- const targets = Array.isArray(assetTargets) ? {
25
- browsers: assetTargets
26
- } : assetTargets;
27
- const targetBrowsers = targets.browsers ?? (await (async () => {
28
- const {
29
- default: browserslist
30
- } = await import('browserslist');
31
- const config = browserslist.findConfig(root);
32
- if (config == null) return ['defaults'];
33
- const targetName = targets.name ?? 'defaults';
34
- return config[targetName] ?? ['defaults'];
35
- })());
36
- const normalizedTargetName = targets.name === 'defaults' ? 'default' : targets.name;
37
- const targetFilenamePart = normalizedTargetName ? `.${normalizedTargetName}` : '';
24
+ const browserTarget = await getBrowserTargetDetails(assets?.targets, {
25
+ root
26
+ });
27
+ const targetFilenamePart = browserTarget.name ? `.${browserTarget.name}` : '';
38
28
  const [{
39
29
  visualizer
40
30
  }, {
41
- assetManifest
31
+ magicModuleEnv,
32
+ replaceProcessEnv
42
33
  }, {
43
34
  sourceCode
44
35
  }, {
@@ -46,16 +37,22 @@ async function quiltAppBrowser({
46
37
  }, {
47
38
  css
48
39
  }, {
40
+ assetManifest,
49
41
  rawAssets,
50
42
  staticAssets
51
43
  }, {
52
44
  systemJS
53
- }, nodePlugins] = await Promise.all([import('rollup-plugin-visualizer'), import('@quilted/assets/rollup'), import('./features/source-code.esnext'), import('./features/typescript.esnext'), import('./features/css.esnext'), import('./features/assets.esnext'), import('./features/system-js.esnext'), getNodePlugins()]);
45
+ }, nodePlugins] = await Promise.all([import('rollup-plugin-visualizer'), import('./features/env.esnext'), import('./features/source-code.esnext'), import('./features/typescript.esnext'), import('./features/css.esnext'), import('./features/assets.esnext'), import('./features/system-js.esnext'), getNodePlugins()]);
54
46
  const plugins = [...nodePlugins, systemJS({
55
47
  minify
48
+ }), replaceProcessEnv({
49
+ mode
50
+ }), magicModuleEnv({
51
+ ...env,
52
+ mode
56
53
  }), sourceCode({
57
54
  mode,
58
- targets: targetBrowsers
55
+ targets: browserTarget.browsers
59
56
  }), css({
60
57
  minify,
61
58
  emit: true
@@ -69,27 +66,6 @@ async function quiltAppBrowser({
69
66
  if (tsconfigAliases) {
70
67
  plugins.push(tsconfigAliases);
71
68
  }
72
- if (env) {
73
- const {
74
- magicModuleEnv,
75
- replaceProcessEnv
76
- } = await import('./features/env.esnext');
77
- if (typeof env === 'boolean') {
78
- plugins.push(replaceProcessEnv({
79
- mode
80
- }));
81
- plugins.push(magicModuleEnv({
82
- mode
83
- }));
84
- } else {
85
- plugins.push(replaceProcessEnv({
86
- mode
87
- }));
88
- plugins.push(magicModuleEnv({
89
- mode
90
- }));
91
- }
92
- }
93
69
  const appEntry = app ?? (await glob('{App,app,input}.{ts,tsx,mjs,js,jsx}', {
94
70
  cwd: root,
95
71
  nodir: true,
@@ -115,17 +91,15 @@ async function quiltAppBrowser({
115
91
  } = await import('rollup-plugin-esbuild');
116
92
  plugins.push(minify());
117
93
  }
118
- const cacheKey = targets.name ? {
119
- browserTarget: targets.name
94
+ const cacheKey = browserTarget.name ? {
95
+ browserTarget: browserTarget.name
120
96
  } : undefined;
121
- const id = targets.name ? targets.name : undefined;
122
- plugins.push(
123
- // @ts-expect-error The plugin still depends on Rollup 3
124
- assetManifest({
97
+ const id = browserTarget.name ? browserTarget.name : undefined;
98
+ plugins.push(assetManifest({
125
99
  id,
126
100
  cacheKey,
127
- baseUrl: baseURL,
128
- path: path.resolve(`build/manifests/assets${targetFilenamePart}.json`),
101
+ baseURL,
102
+ file: path.resolve(`build/manifests/assets${targetFilenamePart}.json`),
129
103
  priority: assets?.priority
130
104
  }), visualizer({
131
105
  template: 'treemap',
@@ -1,8 +1,116 @@
1
1
  import * as path from 'node:path';
2
- import { readFile } from 'node:fs/promises';
2
+ import * as fs from 'node:fs/promises';
3
3
  import { createHash } from 'node:crypto';
4
4
  import * as mime from 'mrmime';
5
5
 
6
+ function assetManifest(manifestOptions) {
7
+ return {
8
+ name: '@quilted/asset-manifest',
9
+ async generateBundle(options, bundle) {
10
+ await writeManifestForBundle.call(this, bundle, manifestOptions, options);
11
+ }
12
+ };
13
+ }
14
+ async function writeManifestForBundle(bundle, {
15
+ id,
16
+ file,
17
+ baseURL,
18
+ cacheKey,
19
+ priority
20
+ }, {
21
+ format
22
+ }) {
23
+ const outputs = Object.values(bundle);
24
+ const entries = outputs.filter(output => output.type === 'chunk' && output.isEntry);
25
+ if (entries.length === 0) {
26
+ throw new Error(`Could not find any entries in your rollup bundle...`);
27
+ }
28
+
29
+ // We assume the first entry is the "main" one. There can be
30
+ // more than one because each worker script is also listed as an
31
+ // entry (though, from a separate build).
32
+ const entryChunk = entries[0];
33
+ const dependencyMap = new Map();
34
+ for (const output of outputs) {
35
+ if (output.type !== 'chunk') continue;
36
+ dependencyMap.set(output.fileName, output.imports);
37
+ }
38
+ const assets = [];
39
+ const assetIdMap = new Map();
40
+ function getAssetId(file) {
41
+ let id = assetIdMap.get(file);
42
+ if (id == null) {
43
+ assets.push(`${baseURL}${file}`);
44
+ id = assets.length - 1;
45
+ assetIdMap.set(file, id);
46
+ }
47
+ return id;
48
+ }
49
+ const manifest = {
50
+ id,
51
+ priority,
52
+ cacheKey,
53
+ assets,
54
+ attributes: format === 'es' ? {
55
+ scripts: {
56
+ type: 'module'
57
+ }
58
+ } : undefined,
59
+ entries: {
60
+ default: createAssetsEntry([...entryChunk.imports, entryChunk.fileName], {
61
+ dependencyMap,
62
+ getAssetId
63
+ })
64
+ },
65
+ modules: {}
66
+ };
67
+ for (const output of outputs) {
68
+ if (output.type !== 'chunk') continue;
69
+ const originalModuleId = output.facadeModuleId ?? output.moduleIds[output.moduleIds.length - 1];
70
+ if (originalModuleId == null) continue;
71
+
72
+ // This metadata is added by the rollup plugin for @quilted/async
73
+ const moduleId = this.getModuleInfo(originalModuleId)?.meta.quilt?.moduleId;
74
+ if (moduleId == null) continue;
75
+ manifest.modules[moduleId] = createAssetsEntry([...output.imports, output.fileName], {
76
+ dependencyMap,
77
+ getAssetId
78
+ });
79
+ }
80
+ await fs.mkdir(path.dirname(file), {
81
+ recursive: true
82
+ });
83
+ await fs.writeFile(file, JSON.stringify(manifest, null, 2));
84
+ }
85
+ function createAssetsEntry(files, {
86
+ dependencyMap,
87
+ getAssetId
88
+ }) {
89
+ const styles = [];
90
+ const scripts = [];
91
+ const allFiles = new Set();
92
+ const addFile = file => {
93
+ if (allFiles.has(file)) return;
94
+ allFiles.add(file);
95
+ for (const dependency of dependencyMap.get(file) ?? []) {
96
+ addFile(dependency);
97
+ }
98
+ };
99
+ for (const file of files) {
100
+ addFile(file);
101
+ }
102
+ for (const file of allFiles) {
103
+ if (file.endsWith('.css')) {
104
+ styles.push(getAssetId(file));
105
+ } else {
106
+ scripts.push(getAssetId(file));
107
+ }
108
+ }
109
+ return {
110
+ scripts,
111
+ styles
112
+ };
113
+ }
6
114
  const QUERY_PATTERN = /\?.*$/s;
7
115
  const HASH_PATTERN = /#.*$/s;
8
116
  const RAW_PATTERN = /(\?|&)raw(?:&|$)/;
@@ -26,7 +134,7 @@ function rawAssets() {
26
134
  }
27
135
  const moduleId = cleanModuleIdentifier(id);
28
136
  this.addWatchFile(moduleId);
29
- const file = await readFile(moduleId, {
137
+ const file = await fs.readFile(moduleId, {
30
138
  encoding: 'utf-8'
31
139
  });
32
140
  return `export default ${JSON.stringify(file)}`;
@@ -53,7 +161,7 @@ function staticAssets({
53
161
  return cached;
54
162
  }
55
163
  const file = cleanModuleIdentifier(id);
56
- const content = await readFile(file);
164
+ const content = await fs.readFile(file);
57
165
  let url;
58
166
  if (!file.endsWith('.svg') && content.length < inlineLimit) {
59
167
  // base64 inlined as a string
@@ -104,4 +212,4 @@ function cleanModuleIdentifier(url) {
104
212
  return url.replace(HASH_PATTERN, '').replace(QUERY_PATTERN, '');
105
213
  }
106
214
 
107
- export { rawAssets, staticAssets };
215
+ export { assetManifest, rawAssets, staticAssets };
@@ -11,7 +11,7 @@ function sourceCode({
11
11
  if (!useBabel) {
12
12
  return esbuild({
13
13
  // Support very modern features
14
- target: 'es2023',
14
+ target: 'es2022',
15
15
  jsx: 'automatic',
16
16
  jsxImportSource: 'react',
17
17
  exclude: 'node_modules/**'
@@ -1,2 +1,3 @@
1
1
  export { quiltAppBrowser, quiltAppServer } from './app.esnext';
2
+ export { quiltModule } from './module.esnext';
2
3
  export { quiltPackageESModules, quiltPackageESNext } from './package.esnext';