@quilted/rollup 0.1.15 → 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.
@@ -0,0 +1,45 @@
1
+ import { Plugin } from 'rollup';
2
+ import { type BrowserTargetSelection } from './shared/browserslist.ts';
3
+ import type { MagicModuleEnvOptions } from './features/env.ts';
4
+ export interface ModuleOptions {
5
+ /**
6
+ * The root directory containing the source code for your application.
7
+ */
8
+ root?: string | URL;
9
+ /**
10
+ * Whether to include GraphQL-related code transformations.
11
+ *
12
+ * @default true
13
+ */
14
+ graphql?: boolean;
15
+ /**
16
+ * Customizes the behavior of environment variables for your module.
17
+ */
18
+ env?: MagicModuleEnvOptions;
19
+ /**
20
+ * Customizes the assets created for your module.
21
+ */
22
+ assets?: ModuleAssetsOptions;
23
+ }
24
+ export interface ModuleAssetsOptions {
25
+ /**
26
+ * Whether to minify assets created for this module.
27
+ *
28
+ * @default true
29
+ */
30
+ minify?: boolean;
31
+ hash?: boolean;
32
+ targets?: BrowserTargetSelection;
33
+ }
34
+ export declare function quiltModule({ root: rootPath, env, assets, graphql, }?: ModuleOptions): Promise<{
35
+ input: string[];
36
+ plugins: Plugin<any>[];
37
+ onwarn(warning: import("rollup").RollupLog, defaultWarn: import("rollup").LoggingFunction): void;
38
+ output: {
39
+ format: "esm";
40
+ dir: string;
41
+ entryFileNames: string;
42
+ assetFileNames: string;
43
+ };
44
+ }>;
45
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../source/module.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAqB,MAAM,QAAQ,CAAC;AAMlD,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,GAAG,CAAC,EAAE,qBAAqB,CAAC;IAE5B;;OAEG;IACH,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED,wBAAsB,WAAW,CAAC,EAChC,IAAI,EAAE,QAAwB,EAC9B,GAAG,EACH,MAAM,EACN,OAAc,GACf,GAAE,aAAkB;;;;;;;;;;GAkFpB"}
@@ -0,0 +1,11 @@
1
+ export type BrowserTargetSelection = string[] | {
2
+ name?: string;
3
+ browsers?: string[];
4
+ };
5
+ export declare function getBrowserTargetDetails(targetSelection?: BrowserTargetSelection, { root }?: {
6
+ root?: string;
7
+ }): Promise<{
8
+ name: string | undefined;
9
+ browsers: string[];
10
+ }>;
11
+ //# sourceMappingURL=browserslist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserslist.d.ts","sourceRoot":"","sources":["../../../source/shared/browserslist.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAC9B,MAAM,EAAE,GACR;IACE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEN,wBAAsB,uBAAuB,CAC3C,eAAe,GAAE,sBAA2B,EAC5C,EAAC,IAAI,EAAC,GAAE;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAM;;;GAsB7B"}
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.1.15",
9
+ "version": "0.1.16",
10
10
  "engines": {
11
11
  "node": ">=14.0.0"
12
12
  },
package/source/app.ts CHANGED
@@ -17,6 +17,10 @@ import type {MagicModuleEnvOptions} from './features/env.ts';
17
17
  import {multiline} from './shared/strings.ts';
18
18
  import {getNodePlugins, removeBuildFiles} from './shared/rollup.ts';
19
19
  import {createMagicModulePlugin} from './shared/magic-module.ts';
20
+ import {
21
+ getBrowserTargetDetails,
22
+ type BrowserTargetSelection,
23
+ } from './shared/browserslist.ts';
20
24
 
21
25
  export interface AppOptions {
22
26
  /**
@@ -58,10 +62,10 @@ export interface AppBrowserOptions extends AppOptions {
58
62
  /**
59
63
  * The entry module for this browser. This should be an absolute path, or relative
60
64
  * path from the root directory containing your project. This entry should be the
61
- * browser entrypoint.
65
+ * browser entrypoint. If you don’t provide a module, Quilt will automatically pick
66
+ *
62
67
  *
63
68
  * @example './browser.tsx'
64
- * @default 'quilt:module/entry'
65
69
  */
66
70
  entry?: string;
67
71
 
@@ -102,12 +106,7 @@ export interface AppBrowserAssetsOptions {
102
106
  minify?: boolean;
103
107
 
104
108
  baseURL?: string;
105
- targets?:
106
- | string[]
107
- | {
108
- name?: string;
109
- browsers?: string[];
110
- };
109
+ targets?: BrowserTargetSelection;
111
110
  priority?: number;
112
111
  }
113
112
 
@@ -126,31 +125,12 @@ export async function quiltAppBrowser({
126
125
  const minify = assets?.minify ?? mode === 'production';
127
126
  const baseURL = assets?.baseURL ?? '/assets/';
128
127
 
129
- const assetTargets = assets?.targets ?? {};
130
- const targets = Array.isArray(assetTargets)
131
- ? {
132
- browsers: assetTargets,
133
- }
134
- : assetTargets;
135
- const targetBrowsers =
136
- targets.browsers ??
137
- (await (async () => {
138
- const {default: browserslist} = await import('browserslist');
139
- const config = browserslist.findConfig(root);
140
-
141
- if (config == null) return ['defaults'];
142
-
143
- const targetName = targets.name ?? 'defaults';
144
- return config[targetName] ?? ['defaults'];
145
- })());
146
- const normalizedTargetName =
147
- targets.name === 'defaults' ? 'default' : targets.name;
148
- const targetFilenamePart = normalizedTargetName
149
- ? `.${normalizedTargetName}`
150
- : '';
128
+ const browserTarget = await getBrowserTargetDetails(assets?.targets, {root});
129
+ const targetFilenamePart = browserTarget.name ? `.${browserTarget.name}` : '';
151
130
 
152
131
  const [
153
132
  {visualizer},
133
+ {magicModuleEnv, replaceProcessEnv},
154
134
  {sourceCode},
155
135
  {createTSConfigAliasPlugin},
156
136
  {css},
@@ -159,6 +139,7 @@ export async function quiltAppBrowser({
159
139
  nodePlugins,
160
140
  ] = await Promise.all([
161
141
  import('rollup-plugin-visualizer'),
142
+ import('./features/env.ts'),
162
143
  import('./features/source-code.ts'),
163
144
  import('./features/typescript.ts'),
164
145
  import('./features/css.ts'),
@@ -170,7 +151,9 @@ export async function quiltAppBrowser({
170
151
  const plugins: Plugin[] = [
171
152
  ...nodePlugins,
172
153
  systemJS({minify}),
173
- sourceCode({mode, targets: targetBrowsers}),
154
+ replaceProcessEnv({mode}),
155
+ magicModuleEnv({...env, mode}),
156
+ sourceCode({mode, targets: browserTarget.browsers}),
174
157
  css({minify, emit: true}),
175
158
  rawAssets(),
176
159
  staticAssets({baseURL, emit: true}),
@@ -185,20 +168,6 @@ export async function quiltAppBrowser({
185
168
  plugins.push(tsconfigAliases);
186
169
  }
187
170
 
188
- if (env) {
189
- const {magicModuleEnv, replaceProcessEnv} = await import(
190
- './features/env.ts'
191
- );
192
-
193
- if (typeof env === 'boolean') {
194
- plugins.push(replaceProcessEnv({mode}));
195
- plugins.push(magicModuleEnv({mode}));
196
- } else {
197
- plugins.push(replaceProcessEnv({mode}));
198
- plugins.push(magicModuleEnv({mode}));
199
- }
200
- }
201
-
202
171
  const appEntry =
203
172
  app ??
204
173
  (await glob('{App,app,input}.{ts,tsx,mjs,js,jsx}', {
@@ -229,8 +198,10 @@ export async function quiltAppBrowser({
229
198
  plugins.push(minify());
230
199
  }
231
200
 
232
- const cacheKey = targets.name ? {browserTarget: targets.name} : undefined;
233
- const id = targets.name ? targets.name : undefined;
201
+ const cacheKey = browserTarget.name
202
+ ? {browserTarget: browserTarget.name}
203
+ : undefined;
204
+ const id = browserTarget.name ? browserTarget.name : undefined;
234
205
 
235
206
  plugins.push(
236
207
  assetManifest({
package/source/index.ts CHANGED
@@ -5,6 +5,7 @@ export {
5
5
  type AppBrowserOptions,
6
6
  type AppServerOptions,
7
7
  } from './app.ts';
8
+ export {quiltModule, type ModuleOptions} from './module.ts';
8
9
  export {
9
10
  quiltPackageESModules,
10
11
  quiltPackageESNext,
@@ -0,0 +1,223 @@
1
+ import * as path from 'path';
2
+ import {Plugin, type RollupOptions} from 'rollup';
3
+ import {glob} from 'glob';
4
+ import {fileURLToPath} from 'url';
5
+
6
+ import {getNodePlugins, removeBuildFiles} from './shared/rollup.ts';
7
+ import {loadPackageJSON, type PackageJSON} from './shared/package-json.ts';
8
+ import {
9
+ getBrowserTargetDetails,
10
+ type BrowserTargetSelection,
11
+ } from './shared/browserslist.ts';
12
+ import type {MagicModuleEnvOptions} from './features/env.ts';
13
+
14
+ export interface ModuleOptions {
15
+ /**
16
+ * The root directory containing the source code for your application.
17
+ */
18
+ root?: string | URL;
19
+
20
+ /**
21
+ * Whether to include GraphQL-related code transformations.
22
+ *
23
+ * @default true
24
+ */
25
+ graphql?: boolean;
26
+
27
+ /**
28
+ * Customizes the behavior of environment variables for your module.
29
+ */
30
+ env?: MagicModuleEnvOptions;
31
+
32
+ /**
33
+ * Customizes the assets created for your module.
34
+ */
35
+ assets?: ModuleAssetsOptions;
36
+ }
37
+
38
+ export interface ModuleAssetsOptions {
39
+ /**
40
+ * Whether to minify assets created for this module.
41
+ *
42
+ * @default true
43
+ */
44
+ minify?: boolean;
45
+ hash?: boolean;
46
+ targets?: BrowserTargetSelection;
47
+ }
48
+
49
+ export async function quiltModule({
50
+ root: rootPath = process.cwd(),
51
+ env,
52
+ assets,
53
+ graphql = true,
54
+ }: ModuleOptions = {}) {
55
+ const root =
56
+ typeof rootPath === 'string' ? rootPath : fileURLToPath(rootPath);
57
+ const mode =
58
+ (typeof env === 'object' ? env?.mode : undefined) ?? 'production';
59
+ const outputDirectory = path.join(root, 'build/assets');
60
+
61
+ const minify = assets?.minify ?? true;
62
+ const hash = assets?.hash ?? true;
63
+ const hashFilenamePart = hash ? '.[hash]' : '';
64
+
65
+ const browserTarget = await getBrowserTargetDetails(assets?.targets, {root});
66
+ const targetFilenamePart = browserTarget.name ? `.${browserTarget.name}` : '';
67
+
68
+ const [
69
+ {visualizer},
70
+ {magicModuleEnv, replaceProcessEnv},
71
+ {sourceCode},
72
+ nodePlugins,
73
+ packageJSON,
74
+ ] = await Promise.all([
75
+ import('rollup-plugin-visualizer'),
76
+ import('./features/env.ts'),
77
+ import('./features/source-code.ts'),
78
+ getNodePlugins(),
79
+ loadPackageJSON(root),
80
+ ]);
81
+
82
+ const source = await sourceForPackage(root, packageJSON);
83
+
84
+ const plugins: Plugin[] = [
85
+ ...nodePlugins,
86
+ replaceProcessEnv({mode}),
87
+ magicModuleEnv({...env, mode}),
88
+ sourceCode({mode: 'production'}),
89
+ removeBuildFiles(['build/assets', 'build/reports'], {root}),
90
+ ];
91
+
92
+ if (graphql) {
93
+ const {graphql} = await import('./features/graphql.ts');
94
+ plugins.push(graphql({manifest: false}));
95
+ }
96
+
97
+ if (minify) {
98
+ const {minify} = await import('rollup-plugin-esbuild');
99
+ plugins.push(minify());
100
+ }
101
+
102
+ plugins.push(
103
+ visualizer({
104
+ template: 'treemap',
105
+ open: false,
106
+ brotliSize: true,
107
+ filename: path.resolve(
108
+ root,
109
+ `build/reports/bundle-visualizer${targetFilenamePart}.html`,
110
+ ),
111
+ }),
112
+ );
113
+
114
+ return {
115
+ input: source.files,
116
+ plugins,
117
+ onwarn(warning, defaultWarn) {
118
+ // Removes annoying warnings for React-focused libraries that
119
+ // include 'use client' directives.
120
+ if (
121
+ warning.code === 'MODULE_LEVEL_DIRECTIVE' &&
122
+ /['"]use client['"]/.test(warning.message)
123
+ ) {
124
+ return;
125
+ }
126
+
127
+ defaultWarn(warning);
128
+ },
129
+ output: {
130
+ format: 'esm',
131
+ dir: outputDirectory,
132
+ entryFileNames: `[name]${targetFilenamePart}${hashFilenamePart}.js`,
133
+ assetFileNames: `[name]${targetFilenamePart}${hashFilenamePart}.[ext]`,
134
+ },
135
+ } satisfies RollupOptions;
136
+ }
137
+
138
+ async function sourceForPackage(root: string, packageJSON: PackageJSON) {
139
+ const [entries] = await Promise.all([
140
+ sourceEntriesForPackage(root, packageJSON),
141
+ ]);
142
+
143
+ let sourceRoot = root;
144
+
145
+ const sourceEntryFiles = Object.values(entries);
146
+
147
+ for (const entry of sourceEntryFiles) {
148
+ if (!entry.startsWith(root)) continue;
149
+
150
+ sourceRoot = path.resolve(
151
+ root,
152
+ path.relative(root, entry).split(path.sep)[0] ?? '.',
153
+ );
154
+ break;
155
+ }
156
+
157
+ return {root: sourceRoot, files: sourceEntryFiles};
158
+ }
159
+
160
+ async function sourceEntriesForPackage(root: string, packageJSON: PackageJSON) {
161
+ const {main, exports} = packageJSON;
162
+
163
+ const entries: Record<string, string> = {};
164
+
165
+ if (typeof main === 'string') {
166
+ entries['.'] = await resolveTargetFileAsSource(main, root);
167
+ }
168
+
169
+ if (typeof exports === 'string') {
170
+ entries['.'] = await resolveTargetFileAsSource(exports, root);
171
+ return entries;
172
+ } else if (exports == null || typeof exports !== 'object') {
173
+ return entries;
174
+ }
175
+
176
+ for (const [exportPath, exportCondition] of Object.entries(
177
+ exports as Record<string, null | string | Record<string, string>>,
178
+ )) {
179
+ let targetFile: string | null | undefined = null;
180
+
181
+ if (exportCondition == null) continue;
182
+
183
+ if (typeof exportCondition === 'string') {
184
+ targetFile = exportCondition;
185
+ } else {
186
+ targetFile ??=
187
+ exportCondition['source'] ??
188
+ exportCondition['quilt:source'] ??
189
+ exportCondition['quilt:esnext'] ??
190
+ Object.values(exportCondition).find(
191
+ (condition) =>
192
+ typeof condition === 'string' && condition.startsWith('./build/'),
193
+ );
194
+ }
195
+
196
+ if (targetFile == null) continue;
197
+
198
+ const sourceFile = await resolveTargetFileAsSource(targetFile, root);
199
+
200
+ entries[exportPath] = sourceFile;
201
+ }
202
+
203
+ return entries;
204
+ }
205
+
206
+ async function resolveTargetFileAsSource(file: string, root: string) {
207
+ const sourceFile = file.includes('/build/')
208
+ ? (
209
+ await glob(
210
+ file
211
+ .replace(/[/]build[/][^/]+[/]/, '/*/')
212
+ .replace(/(\.d\.ts|\.[\w]+)$/, '.*'),
213
+ {
214
+ cwd: root,
215
+ absolute: true,
216
+ ignore: [path.resolve(root, file)],
217
+ },
218
+ )
219
+ )[0]!
220
+ : path.resolve(root, file);
221
+
222
+ return sourceFile;
223
+ }
@@ -0,0 +1,32 @@
1
+ export type BrowserTargetSelection =
2
+ | string[]
3
+ | {
4
+ name?: string;
5
+ browsers?: string[];
6
+ };
7
+
8
+ export async function getBrowserTargetDetails(
9
+ targetSelection: BrowserTargetSelection = {},
10
+ {root}: {root?: string} = {},
11
+ ) {
12
+ const targets = Array.isArray(targetSelection)
13
+ ? {
14
+ browsers: targetSelection,
15
+ }
16
+ : targetSelection;
17
+ const targetBrowsers =
18
+ targets.browsers ??
19
+ (await (async () => {
20
+ const {default: browserslist} = await import('browserslist');
21
+ const config = browserslist.findConfig(root!);
22
+
23
+ if (config == null) return ['defaults'];
24
+
25
+ const targetName = targets.name ?? 'defaults';
26
+ return config[targetName] ?? ['defaults'];
27
+ })());
28
+
29
+ const name = targets.name === 'defaults' ? 'default' : targets.name;
30
+
31
+ return {name, browsers: targetBrowsers};
32
+ }