@quilted/rollup 0.2.39 → 0.2.40

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.
@@ -1,9 +1,9 @@
1
1
  import type { Plugin, PluginContext } from 'rollup';
2
2
  export interface AssetManifestOptions {
3
3
  file: string;
4
- baseURL: string;
4
+ key?: URLSearchParams;
5
+ base: string;
5
6
  priority?: number;
6
- cacheKey?: URLSearchParams;
7
7
  moduleID?(details: {
8
8
  imported: string;
9
9
  }): string;
@@ -1 +1 @@
1
- {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../source/features/assets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAIV,MAAM,EACN,aAAa,EACd,MAAM,QAAQ,CAAC;AAQhB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,CAAC,OAAO,EAAE;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM,CAAC;CAChD;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,oBAAoB,GAAG,MAAM,CAO3E;AA2KD,wBAAgB,SAAS,IAAI,MAAM,CAmBlC;AAED,wBAAgB,YAAY,CAAC,EAC3B,IAAW,EACX,OAAa,EACb,UAA4C,EAC5C,WAAkC,EAClC,aAAsC,GACvC,GAAE;IACD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACnB;;;EA+DL"}
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../source/features/assets.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAIV,MAAM,EACN,aAAa,EACd,MAAM,QAAQ,CAAC;AAKhB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,CAAC,OAAO,EAAE;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM,CAAC;CAChD;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,oBAAoB,GAAG,MAAM,CAO3E;AA2KD,wBAAgB,SAAS,IAAI,MAAM,CAmBlC;AAED,wBAAgB,YAAY,CAAC,EAC3B,IAAW,EACX,OAAa,EACb,UAA4C,EAC5C,WAAkC,EAClC,aAAsC,GACvC,GAAE;IACD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACnB;;;EA+DL"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "access": "public",
7
7
  "@quilted/registry": "https://registry.npmjs.org"
8
8
  },
9
- "version": "0.2.39",
9
+ "version": "0.2.40",
10
10
  "engines": {
11
11
  "node": ">=14.0.0"
12
12
  },
@@ -143,7 +143,7 @@
143
143
  "@rollup/plugin-commonjs": "^25.0.5",
144
144
  "@rollup/plugin-json": "^6.0.1",
145
145
  "@rollup/plugin-node-resolve": "^15.2.3",
146
- "@quilted/assets": "^0.1.0",
146
+ "@quilted/assets": "^0.1.3",
147
147
  "@quilted/babel": "^0.2.2",
148
148
  "@quilted/graphql": "^3.3.4",
149
149
  "@types/babel__preset-env": "^7.9.0",
package/source/app.ts CHANGED
@@ -8,7 +8,7 @@ import type {
8
8
  InputPluginOption,
9
9
  GetManualChunk,
10
10
  } from 'rollup';
11
- import type {AssetsBuildManifest} from '@quilted/assets';
11
+ import type {AssetBuildManifest} from '@quilted/assets';
12
12
 
13
13
  import {
14
14
  MAGIC_MODULE_ENTRY,
@@ -614,11 +614,10 @@ export async function quiltAppBrowserPlugins({
614
614
 
615
615
  plugins.push(
616
616
  assetManifest({
617
- baseURL,
618
- cacheKey,
617
+ key: cacheKey,
618
+ base: baseURL,
619
619
  file: path.join(manifestsDirectory, `assets${targetFilenamePart}.json`),
620
620
  priority: assets?.priority,
621
- moduleID: ({imported}) => path.relative(project.root, imported),
622
621
  }),
623
622
  visualizer({
624
623
  template: 'treemap',
@@ -638,6 +637,8 @@ export function quiltAppBrowserInput({
638
637
  root,
639
638
  entry,
640
639
  }: Pick<AppBrowserOptions, 'root' | 'entry'> = {}) {
640
+ const MODULES_TO_ENTRIES = new Map<string, string>();
641
+
641
642
  return {
642
643
  name: '@quilted/app-browser/input',
643
644
  async options(options) {
@@ -649,6 +650,15 @@ export function quiltAppBrowserInput({
649
650
  typeof finalEntry === 'string' && finalEntry !== MAGIC_MODULE_ENTRY
650
651
  ? path.basename(finalEntry).split('.').slice(0, -1).join('.')
651
652
  : 'browser';
653
+ const additionalEntries = await additionalEntriesForAppBrowser({root});
654
+
655
+ if (typeof finalEntry === 'string') {
656
+ MODULES_TO_ENTRIES.set(finalEntry, '.');
657
+ }
658
+
659
+ for (const [name, entry] of Object.entries(additionalEntries)) {
660
+ MODULES_TO_ENTRIES.set(entry, `./${name}`);
661
+ }
652
662
 
653
663
  return {
654
664
  ...options,
@@ -656,10 +666,24 @@ export function quiltAppBrowserInput({
656
666
  // Otherwise, Rollup will use the file name as the output name.
657
667
  input:
658
668
  typeof finalEntry === 'string'
659
- ? {[finalEntryName]: finalEntry}
660
- : finalEntry,
669
+ ? {...additionalEntries, [finalEntryName]: finalEntry}
670
+ : Array.isArray(finalEntry)
671
+ ? finalEntry
672
+ : {...additionalEntries, ...finalEntry},
661
673
  };
662
674
  },
675
+ resolveId(source, importer, options) {
676
+ const entry = MODULES_TO_ENTRIES.get(source);
677
+ if (entry == null) return null;
678
+
679
+ return this.resolve(source, importer, {...options, skipSelf: true}).then(
680
+ (resolved) => {
681
+ return resolved
682
+ ? {...resolved, meta: {...resolved.meta, quilt: {entry}}}
683
+ : resolved;
684
+ },
685
+ );
686
+ },
663
687
  } satisfies Plugin;
664
688
  }
665
689
 
@@ -1152,17 +1176,6 @@ export function magicModuleAppComponent({
1152
1176
  entry ??
1153
1177
  async function magicModuleApp() {
1154
1178
  const project = Project.load(root);
1155
- const {packageJSON} = project;
1156
-
1157
- if (typeof packageJSON.raw.main === 'string') {
1158
- return project.resolve(packageJSON.raw.main);
1159
- }
1160
-
1161
- const rootEntry = (packageJSON.raw.exports as any)?.['.'];
1162
-
1163
- if (typeof rootEntry === 'string') {
1164
- return project.resolve(rootEntry);
1165
- }
1166
1179
 
1167
1180
  const globbed = await project.glob(
1168
1181
  '{App,app,index}.{ts,tsx,mjs,js,jsx}',
@@ -1184,7 +1197,7 @@ export function magicModuleAppRequestRouter({
1184
1197
  return createMagicModulePlugin({
1185
1198
  name: '@quilted/magic-module/app-request-router',
1186
1199
  module: MAGIC_MODULE_REQUEST_ROUTER,
1187
- alias: () => appServerEntry({entry, root}) as Promise<string>,
1200
+ alias: () => sourceEntryForAppServer({entry, root}) as Promise<string>,
1188
1201
  async source() {
1189
1202
  return multiline`
1190
1203
  import '@quilted/quilt/globals';
@@ -1217,25 +1230,6 @@ export function magicModuleAppRequestRouter({
1217
1230
  });
1218
1231
  }
1219
1232
 
1220
- export async function appServerEntry({
1221
- entry,
1222
- root = process.cwd(),
1223
- }: Pick<AppServerOptions, 'entry' | 'root'> = {}) {
1224
- if (entry) return entry;
1225
-
1226
- const project = Project.load(root);
1227
-
1228
- const globbed = await project.glob(
1229
- '{server,service,backend}.{ts,tsx,mjs,js,jsx}',
1230
- {
1231
- nodir: true,
1232
- absolute: true,
1233
- },
1234
- );
1235
-
1236
- return globbed[0];
1237
- }
1238
-
1239
1233
  export function magicModuleAppBrowserEntry({
1240
1234
  hydrate = true,
1241
1235
  selector = '#app',
@@ -1279,7 +1273,7 @@ export function magicModuleAppAssetManifests() {
1279
1273
  const manifests = await Promise.all(
1280
1274
  manifestFiles.map(
1281
1275
  async (file) =>
1282
- JSON.parse(await fs.readFile(file, 'utf8')) as AssetsBuildManifest,
1276
+ JSON.parse(await fs.readFile(file, 'utf8')) as AssetBuildManifest,
1283
1277
  ),
1284
1278
  );
1285
1279
 
@@ -1346,6 +1340,39 @@ export async function sourceEntryForAppBrowser({
1346
1340
  if (entry) {
1347
1341
  return project.resolve(entry);
1348
1342
  } else {
1343
+ const {packageJSON} = project;
1344
+
1345
+ // If we have a `main` or `browser` field in our `package.json`, use that
1346
+ // as the browser entry.
1347
+ if (typeof packageJSON.raw.main === 'string') {
1348
+ return project.resolve(packageJSON.raw.main);
1349
+ }
1350
+
1351
+ if (typeof packageJSON.raw.browser === 'string') {
1352
+ return project.resolve(packageJSON.raw.browser);
1353
+ }
1354
+
1355
+ // Try `package.json` `exports` field, if it’s a string or an object with export conditions
1356
+ let currentEntry = packageJSON.raw.exports as any;
1357
+ let resolvedEntryFromExports = resolveExportsField(
1358
+ project,
1359
+ currentEntry,
1360
+ BROWSER_EXPORT_CONDITIONS,
1361
+ );
1362
+
1363
+ if (resolvedEntryFromExports) return resolvedEntryFromExports;
1364
+
1365
+ // Then, try `exports[.]`, if it’s a string or an object with export conditions
1366
+ currentEntry = currentEntry?.['.'];
1367
+ resolvedEntryFromExports = resolveExportsField(
1368
+ project,
1369
+ currentEntry,
1370
+ BROWSER_EXPORT_CONDITIONS,
1371
+ );
1372
+
1373
+ if (resolvedEntryFromExports) return resolvedEntryFromExports;
1374
+
1375
+ // If we don’t have an entry yet, try the default file names
1349
1376
  const files = await project.glob(
1350
1377
  '{browser,client,web}.{ts,tsx,mjs,js,jsx}',
1351
1378
  {
@@ -1358,6 +1385,72 @@ export async function sourceEntryForAppBrowser({
1358
1385
  }
1359
1386
  }
1360
1387
 
1388
+ const BROWSER_EXPORT_CONDITIONS = new Set([
1389
+ 'browser',
1390
+ 'source',
1391
+ 'quilt:source',
1392
+ 'default',
1393
+ ]);
1394
+ const SERVER_EXPORT_CONDITIONS = new Set([
1395
+ 'server',
1396
+ 'source',
1397
+ 'quilt:source',
1398
+ 'default',
1399
+ ]);
1400
+
1401
+ async function additionalEntriesForAppBrowser({
1402
+ root = process.cwd(),
1403
+ }: {
1404
+ root?: string | URL;
1405
+ }) {
1406
+ const additionalEntries: Record<string, string> = {};
1407
+
1408
+ const project = Project.load(root);
1409
+ const exports = project.packageJSON.raw.exports as any;
1410
+
1411
+ if (typeof exports === 'object' && exports != null) {
1412
+ for (const [key, value] of Object.entries(exports)) {
1413
+ // skip anything other than entries
1414
+ if (!key.startsWith('.')) continue;
1415
+
1416
+ // Skip the `.` key, since it’s not an additional entry
1417
+ if (key === '.') continue;
1418
+
1419
+ const resolvedEntry = resolveExportsField(
1420
+ project,
1421
+ value as any,
1422
+ BROWSER_EXPORT_CONDITIONS,
1423
+ );
1424
+
1425
+ if (resolvedEntry) {
1426
+ additionalEntries[key.slice(2)] = resolvedEntry;
1427
+ }
1428
+ }
1429
+ }
1430
+
1431
+ return additionalEntries;
1432
+ }
1433
+
1434
+ function resolveExportsField(
1435
+ project: Project,
1436
+ entry:
1437
+ | string
1438
+ | null
1439
+ | undefined
1440
+ | Record<string, string | null | undefined | Record<string, unknown>>,
1441
+ conditions: Set<string>,
1442
+ ) {
1443
+ if (typeof entry === 'string') {
1444
+ return project.resolve(entry);
1445
+ } else if (typeof entry === 'object' && entry != null) {
1446
+ for (const [condition, value] of Object.entries(entry)) {
1447
+ if (conditions.has(condition) && typeof value === 'string') {
1448
+ return project.resolve(value);
1449
+ }
1450
+ }
1451
+ }
1452
+ }
1453
+
1361
1454
  export async function sourceEntryForAppServer({
1362
1455
  entry,
1363
1456
  root = process.cwd(),
@@ -1369,7 +1462,21 @@ export async function sourceEntryForAppServer({
1369
1462
 
1370
1463
  if (entry) {
1371
1464
  return project.resolve(entry);
1372
- } else {
1465
+ }
1466
+ {
1467
+ const {packageJSON} = project;
1468
+
1469
+ // Try `package.json` `exports` field, if it has a `server` condition or a `.`
1470
+ // enrty with a `server` condition
1471
+ const exports = packageJSON.raw.exports as any;
1472
+
1473
+ const resolvedFromRootServerEntry = resolveExportsField(
1474
+ project,
1475
+ exports?.['server'] ?? exports?.['.']?.['server'],
1476
+ SERVER_EXPORT_CONDITIONS,
1477
+ );
1478
+ if (resolvedFromRootServerEntry) return resolvedFromRootServerEntry;
1479
+
1373
1480
  const files = await project.glob(
1374
1481
  '{server,service,backend}.{ts,tsx,mjs,js,jsx}',
1375
1482
  {
@@ -11,16 +11,13 @@ import type {
11
11
  } from 'rollup';
12
12
  import * as mime from 'mrmime';
13
13
 
14
- import type {
15
- AssetsBuildManifest,
16
- AssetsBuildManifestEntry,
17
- } from '@quilted/assets';
14
+ import type {AssetBuildManifest, AssetBuildAsset} from '@quilted/assets';
18
15
 
19
16
  export interface AssetManifestOptions {
20
17
  file: string;
21
- baseURL: string;
18
+ key?: URLSearchParams;
19
+ base: string;
22
20
  priority?: number;
23
- cacheKey?: URLSearchParams;
24
21
  moduleID?(details: {imported: string}): string;
25
22
  }
26
23
 
@@ -38,8 +35,8 @@ async function writeManifestForBundle(
38
35
  bundle: OutputBundle,
39
36
  {
40
37
  file,
41
- baseURL,
42
- cacheKey,
38
+ base,
39
+ key,
43
40
  priority,
44
41
  moduleID: getModuleID = defaultModuleID,
45
42
  }: AssetManifestOptions,
@@ -56,11 +53,6 @@ async function writeManifestForBundle(
56
53
  throw new Error(`Could not find any entries in your rollup bundle...`);
57
54
  }
58
55
 
59
- // We assume the first entry is the "main" one. There can be
60
- // more than one because each worker script is also listed as an
61
- // entry (though, from a separate build).
62
- const entryChunk = entries[0]!;
63
-
64
56
  const dependencyMap = new Map<string, string[]>();
65
57
 
66
58
  for (const output of outputs) {
@@ -68,14 +60,14 @@ async function writeManifestForBundle(
68
60
  dependencyMap.set(output.fileName, output.imports);
69
61
  }
70
62
 
71
- const assets: string[] = [];
63
+ const assets: AssetBuildAsset[] = [];
72
64
  const assetIdMap = new Map<string, number>();
73
65
 
74
66
  function getAssetId(file: string) {
75
67
  let id = assetIdMap.get(file);
76
68
 
77
69
  if (id == null) {
78
- assets.push(`${baseURL}${file}`);
70
+ assets.push([file.endsWith('.css') ? 1 : 2, file]);
79
71
  id = assets.length - 1;
80
72
  assetIdMap.set(file, id);
81
73
  }
@@ -83,34 +75,40 @@ async function writeManifestForBundle(
83
75
  return id;
84
76
  }
85
77
 
86
- const manifest: AssetsBuildManifest = {
78
+ const manifest: AssetBuildManifest = {
79
+ key: key && key.size > 0 ? key.toString() : undefined,
80
+ base,
87
81
  priority,
88
- cacheKey: cacheKey && cacheKey.size > 0 ? cacheKey.toString() : undefined,
89
82
  assets,
90
- attributes: format === 'es' ? {scripts: {type: 'module'}} : undefined,
91
- entries: {
92
- default: createAssetsEntry([...entryChunk.imports, entryChunk.fileName], {
93
- dependencyMap,
94
- getAssetId,
95
- }),
96
- },
83
+ attributes: format === 'es' ? {2: {type: 'module'}} : undefined,
84
+ entries: {} as any,
97
85
  modules: {},
98
86
  };
99
87
 
100
88
  for (const output of outputs) {
101
- if (output.type !== 'chunk' || !output.isDynamicEntry) continue;
89
+ if (
90
+ output.type !== 'chunk' ||
91
+ (!output.isDynamicEntry && !output.isEntry)
92
+ ) {
93
+ continue;
94
+ }
102
95
 
103
96
  const rollupModuleID = output.facadeModuleId ?? output.moduleIds.at(-1);
104
97
 
105
98
  if (rollupModuleID == null) continue;
106
99
 
107
- const imported =
108
- this.getModuleInfo(rollupModuleID)?.meta?.quilt?.module ?? rollupModuleID;
100
+ const moduleInfo = this.getModuleInfo(rollupModuleID);
101
+ const imported = moduleInfo?.meta?.quilt?.module ?? rollupModuleID;
109
102
 
110
103
  const moduleID = getModuleID({imported: imported});
111
104
 
112
105
  if (moduleID == null) continue;
113
106
 
107
+ if (output.isEntry) {
108
+ const entry = moduleInfo?.meta?.quilt?.entry ?? moduleID;
109
+ manifest.entries[entry] = moduleID;
110
+ }
111
+
114
112
  manifest.modules[moduleID] = createAssetsEntry(
115
113
  [...output.imports, output.fileName],
116
114
  {dependencyMap, getAssetId},
@@ -122,7 +120,11 @@ async function writeManifestForBundle(
122
120
  }
123
121
 
124
122
  function defaultModuleID({imported}: {imported: string}) {
125
- return path.relative(process.cwd(), imported).replace(/[\\/]/g, '-');
123
+ return imported.startsWith('/')
124
+ ? path.relative(process.cwd(), imported)
125
+ : imported.startsWith('\0')
126
+ ? imported.replace('\0', '')
127
+ : imported;
126
128
  }
127
129
 
128
130
  function createAssetsEntry(
@@ -134,9 +136,8 @@ function createAssetsEntry(
134
136
  dependencyMap: Map<string, string[]>;
135
137
  getAssetId(file: string): number;
136
138
  },
137
- ): AssetsBuildManifestEntry {
138
- const styles: number[] = [];
139
- const scripts: number[] = [];
139
+ ) {
140
+ const assets: number[] = [];
140
141
 
141
142
  const allFiles = new Set<string>();
142
143
  const addFile = (file: string) => {
@@ -153,14 +154,10 @@ function createAssetsEntry(
153
154
  }
154
155
 
155
156
  for (const file of allFiles) {
156
- if (file.endsWith('.css')) {
157
- styles.push(getAssetId(file));
158
- } else {
159
- scripts.push(getAssetId(file));
160
- }
157
+ assets.push(getAssetId(file));
161
158
  }
162
159
 
163
- return {scripts, styles};
160
+ return assets;
164
161
  }
165
162
 
166
163
  const QUERY_PATTERN = /\?.*$/s;