@quilted/rollup 0.1.4 → 0.1.6
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.
- package/CHANGELOG.md +18 -0
- package/build/cjs/app.cjs +160 -142
- package/build/cjs/features/assets.cjs +130 -0
- package/build/cjs/features/css.cjs +71 -0
- package/build/cjs/{env.cjs → features/env.cjs} +4 -4
- package/build/cjs/{request-router.cjs → features/request-router.cjs} +3 -3
- package/build/cjs/{shared → features}/source-code.cjs +7 -2
- package/build/cjs/features/system-js.cjs +35 -0
- package/build/cjs/index.cjs +0 -7
- package/build/cjs/shared/rollup.cjs +0 -4
- package/build/esm/app.mjs +162 -144
- package/build/esm/features/assets.mjs +107 -0
- package/build/esm/features/css.mjs +69 -0
- package/build/esm/{env.mjs → features/env.mjs} +4 -4
- package/build/esm/{request-router.mjs → features/request-router.mjs} +3 -3
- package/build/esm/{shared → features}/source-code.mjs +6 -1
- package/build/esm/features/system-js.mjs +33 -0
- package/build/esm/index.mjs +1 -3
- package/build/esm/shared/rollup.mjs +1 -4
- package/build/esnext/app.esnext +162 -144
- package/build/esnext/features/assets.esnext +107 -0
- package/build/esnext/features/css.esnext +69 -0
- package/build/esnext/{env.esnext → features/env.esnext} +4 -4
- package/build/esnext/{request-router.esnext → features/request-router.esnext} +3 -3
- package/build/esnext/{shared → features}/source-code.esnext +6 -1
- package/build/esnext/features/system-js.esnext +33 -0
- package/build/esnext/index.esnext +1 -3
- package/build/esnext/shared/rollup.esnext +1 -4
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/typescript/app.d.ts +33 -144
- package/build/typescript/app.d.ts.map +1 -1
- package/build/typescript/features/assets.d.ts +13 -0
- package/build/typescript/features/assets.d.ts.map +1 -0
- package/build/typescript/features/css.d.ts +16 -0
- package/build/typescript/features/css.d.ts.map +1 -0
- package/build/typescript/features/env.d.ts +57 -0
- package/build/typescript/features/env.d.ts.map +1 -0
- package/build/typescript/features/graphql/transform.d.ts +17 -0
- package/build/typescript/features/graphql/transform.d.ts.map +1 -0
- package/build/typescript/features/graphql.d.ts +6 -0
- package/build/typescript/features/graphql.d.ts.map +1 -0
- package/build/typescript/features/request-router.d.ts +15 -0
- package/build/typescript/features/request-router.d.ts.map +1 -0
- package/build/typescript/features/source-code.d.ts +5 -0
- package/build/typescript/features/source-code.d.ts.map +1 -0
- package/build/typescript/features/system-js.d.ts +7 -0
- package/build/typescript/features/system-js.d.ts.map +1 -0
- package/build/typescript/index.d.ts +1 -3
- package/build/typescript/index.d.ts.map +1 -1
- package/package.json +5 -2
- package/source/app.ts +184 -122
- package/source/features/assets.ts +183 -0
- package/source/features/css.ts +91 -0
- package/source/{env.ts → features/env.ts} +4 -4
- package/source/{request-router.ts → features/request-router.ts} +3 -3
- package/source/{shared → features}/source-code.ts +3 -0
- package/source/features/system-js.ts +36 -0
- package/source/index.ts +0 -5
- /package/build/cjs/{graphql → features/graphql}/transform.cjs +0 -0
- /package/build/cjs/{graphql.cjs → features/graphql.cjs} +0 -0
- /package/build/esm/{graphql → features/graphql}/transform.mjs +0 -0
- /package/build/esm/{graphql.mjs → features/graphql.mjs} +0 -0
- /package/build/esnext/{graphql → features/graphql}/transform.esnext +0 -0
- /package/build/esnext/{graphql.esnext → features/graphql.esnext} +0 -0
- /package/source/{graphql → features/graphql}/transform.ts +0 -0
- /package/source/{graphql.ts → features/graphql.ts} +0 -0
package/source/app.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {Plugin, RollupOptions, GetManualChunk} from 'rollup';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
MAGIC_MODULE_ENTRY,
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
MAGIC_MODULE_BROWSER_ASSETS,
|
|
9
9
|
MAGIC_MODULE_REQUEST_ROUTER,
|
|
10
10
|
} from './constants.ts';
|
|
11
|
-
import type {MagicModuleEnvOptions} from './env.ts';
|
|
11
|
+
import type {MagicModuleEnvOptions} from './features/env.ts';
|
|
12
12
|
|
|
13
13
|
import {multiline} from './shared/strings.ts';
|
|
14
|
-
import {getNodePlugins
|
|
14
|
+
import {getNodePlugins} from './shared/rollup.ts';
|
|
15
15
|
import {createMagicModulePlugin} from './shared/magic-module.ts';
|
|
16
16
|
|
|
17
17
|
export interface AppOptions {
|
|
@@ -22,8 +22,9 @@ export interface AppOptions {
|
|
|
22
22
|
* to create browser and server-side entries for your project.
|
|
23
23
|
*
|
|
24
24
|
* If you only want to use a custom entry module for the browser build, use the
|
|
25
|
-
* `
|
|
26
|
-
* for the server-side build, use the `server.entry` option
|
|
25
|
+
* `entry` option of the `quiltAppBrowser()` instead. If you only want to use a
|
|
26
|
+
* custom entry module for the server-side build, use the `server.entry` option
|
|
27
|
+
* instead.
|
|
27
28
|
*
|
|
28
29
|
* @example './App.tsx'
|
|
29
30
|
*/
|
|
@@ -46,7 +47,18 @@ export interface AppOptions {
|
|
|
46
47
|
|
|
47
48
|
export interface AppBrowserOptions extends AppOptions {
|
|
48
49
|
/**
|
|
49
|
-
*
|
|
50
|
+
* The entry module for this browser. This should be an absolute path, or relative
|
|
51
|
+
* path from the root directory containing your project. This entry should be the
|
|
52
|
+
* browser entrypoint.
|
|
53
|
+
*
|
|
54
|
+
* @example './browser.tsx'
|
|
55
|
+
* @default 'quilt:module/entry'
|
|
56
|
+
*/
|
|
57
|
+
entry?: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Customizes the magic `quilt:module/entry` module, which can be used as a "magic"
|
|
61
|
+
* entry for your application.
|
|
50
62
|
*/
|
|
51
63
|
module?: AppBrowserModuleOptions;
|
|
52
64
|
|
|
@@ -81,8 +93,9 @@ export interface AppBrowserAssetsOptions {
|
|
|
81
93
|
minify?: boolean;
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
export function quiltAppBrowser({
|
|
96
|
+
export async function quiltAppBrowser({
|
|
85
97
|
app,
|
|
98
|
+
entry = MAGIC_MODULE_ENTRY,
|
|
86
99
|
env,
|
|
87
100
|
assets,
|
|
88
101
|
module,
|
|
@@ -90,78 +103,97 @@ export function quiltAppBrowser({
|
|
|
90
103
|
}: AppBrowserOptions = {}) {
|
|
91
104
|
const mode =
|
|
92
105
|
(typeof env === 'object' ? env?.mode : undefined) ?? 'production';
|
|
106
|
+
const minify = assets?.minify ?? mode === 'production';
|
|
107
|
+
|
|
108
|
+
const [
|
|
109
|
+
{visualizer},
|
|
110
|
+
{sourceCode},
|
|
111
|
+
{css},
|
|
112
|
+
{rawAssets, staticAssets},
|
|
113
|
+
{systemJS},
|
|
114
|
+
nodePlugins,
|
|
115
|
+
] = await Promise.all([
|
|
116
|
+
import('rollup-plugin-visualizer'),
|
|
117
|
+
import('./features/source-code.ts'),
|
|
118
|
+
import('./features/css.ts'),
|
|
119
|
+
import('./features/assets.ts'),
|
|
120
|
+
import('./features/system-js.ts'),
|
|
121
|
+
getNodePlugins(),
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
const plugins: Plugin[] = [
|
|
125
|
+
...nodePlugins,
|
|
126
|
+
systemJS(),
|
|
127
|
+
sourceCode({mode}),
|
|
128
|
+
css({minify}),
|
|
129
|
+
rawAssets(),
|
|
130
|
+
staticAssets(),
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
if (env) {
|
|
134
|
+
const {magicModuleEnv, replaceProcessEnv} = await import(
|
|
135
|
+
'./features/env.ts'
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (typeof env === 'boolean') {
|
|
139
|
+
plugins.push(replaceProcessEnv({mode}));
|
|
140
|
+
plugins.push(magicModuleEnv({mode}));
|
|
141
|
+
} else {
|
|
142
|
+
plugins.push(replaceProcessEnv({mode}));
|
|
143
|
+
plugins.push(magicModuleEnv({mode}));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
93
146
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const newPlugins = rollupPluginsToArray(originalOptions.plugins);
|
|
98
|
-
const newOptions = {...originalOptions, plugins: newPlugins};
|
|
99
|
-
|
|
100
|
-
const [{visualizer}, {sourceCode}, nodePlugins] = await Promise.all([
|
|
101
|
-
import('rollup-plugin-visualizer'),
|
|
102
|
-
import('./shared/source-code.ts'),
|
|
103
|
-
getNodePlugins(),
|
|
104
|
-
]);
|
|
105
|
-
|
|
106
|
-
newPlugins.push(...nodePlugins);
|
|
107
|
-
newPlugins.push(sourceCode({mode}));
|
|
108
|
-
|
|
109
|
-
if (env) {
|
|
110
|
-
const {magicModuleEnv, replaceProcessEnv} = await import('./env.ts');
|
|
111
|
-
|
|
112
|
-
if (typeof env === 'boolean') {
|
|
113
|
-
newPlugins.push(replaceProcessEnv({mode: 'production'}));
|
|
114
|
-
newPlugins.push(magicModuleEnv({mode: 'production'}));
|
|
115
|
-
} else {
|
|
116
|
-
newPlugins.push(replaceProcessEnv({mode: env.mode ?? 'production'}));
|
|
117
|
-
newPlugins.push(magicModuleEnv({mode: 'production', ...env}));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
147
|
+
if (app) {
|
|
148
|
+
plugins.push(magicModuleAppComponent({entry: app}));
|
|
149
|
+
}
|
|
120
150
|
|
|
121
|
-
|
|
122
|
-
newPlugins.push(magicModuleAppComponent({entry: app}));
|
|
123
|
-
}
|
|
151
|
+
plugins.push(magicModuleAppBrowserEntry(module));
|
|
124
152
|
|
|
125
|
-
|
|
153
|
+
if (graphql) {
|
|
154
|
+
const {graphql} = await import('./features/graphql.ts');
|
|
155
|
+
plugins.push(graphql({manifest: path.resolve(`manifests/graphql.json`)}));
|
|
156
|
+
}
|
|
126
157
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
);
|
|
132
|
-
}
|
|
158
|
+
if (minify) {
|
|
159
|
+
const {minify} = await import('rollup-plugin-esbuild');
|
|
160
|
+
plugins.push(minify());
|
|
161
|
+
}
|
|
133
162
|
|
|
134
|
-
|
|
163
|
+
plugins.push(
|
|
164
|
+
visualizer({
|
|
165
|
+
template: 'treemap',
|
|
166
|
+
open: false,
|
|
167
|
+
brotliSize: true,
|
|
168
|
+
filename: path.resolve(`reports/bundle-visualizer.html`),
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
135
171
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
172
|
+
return {
|
|
173
|
+
input: entry,
|
|
174
|
+
plugins,
|
|
175
|
+
onwarn(warning, defaultWarn) {
|
|
176
|
+
// Removes annoying warnings for React-focused libraries that
|
|
177
|
+
// include 'use client' directives.
|
|
178
|
+
if (
|
|
179
|
+
warning.code === 'MODULE_LEVEL_DIRECTIVE' &&
|
|
180
|
+
/['"]use client['"]/.test(warning.message)
|
|
181
|
+
) {
|
|
182
|
+
return;
|
|
139
183
|
}
|
|
140
184
|
|
|
141
|
-
|
|
142
|
-
visualizer({
|
|
143
|
-
template: 'treemap',
|
|
144
|
-
open: false,
|
|
145
|
-
brotliSize: true,
|
|
146
|
-
filename: path.resolve(`reports/bundle-visualizer.html`),
|
|
147
|
-
}),
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
return newOptions;
|
|
185
|
+
defaultWarn(warning);
|
|
151
186
|
},
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
chunkFileNames: `[name].[hash].js`,
|
|
161
|
-
manualChunks: createManualChunksSorter(),
|
|
162
|
-
};
|
|
187
|
+
output: {
|
|
188
|
+
// format: isESM ? 'esm' : 'systemjs',
|
|
189
|
+
format: 'esm',
|
|
190
|
+
dir: path.resolve(`build/assets`),
|
|
191
|
+
entryFileNames: `app.[hash].js`,
|
|
192
|
+
assetFileNames: `[name].[hash].[ext]`,
|
|
193
|
+
chunkFileNames: `[name].[hash].js`,
|
|
194
|
+
manualChunks: createManualChunksSorter(),
|
|
163
195
|
},
|
|
164
|
-
} satisfies
|
|
196
|
+
} satisfies RollupOptions;
|
|
165
197
|
}
|
|
166
198
|
|
|
167
199
|
export interface AppServerOptions extends AppOptions {
|
|
@@ -171,69 +203,99 @@ export interface AppServerOptions extends AppOptions {
|
|
|
171
203
|
* the specific server runtime you configure.
|
|
172
204
|
*/
|
|
173
205
|
entry?: string;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Whether to minify the JavaScript outputs for your server.
|
|
209
|
+
*
|
|
210
|
+
* @default false
|
|
211
|
+
*/
|
|
212
|
+
minify?: boolean;
|
|
174
213
|
}
|
|
175
214
|
|
|
176
|
-
export function quiltAppServer({
|
|
215
|
+
export async function quiltAppServer({
|
|
177
216
|
app,
|
|
178
217
|
env,
|
|
179
|
-
graphql,
|
|
180
|
-
entry,
|
|
218
|
+
graphql = true,
|
|
219
|
+
entry = MAGIC_MODULE_ENTRY,
|
|
220
|
+
minify = false,
|
|
181
221
|
}: AppServerOptions = {}) {
|
|
182
222
|
const mode =
|
|
183
223
|
(typeof env === 'object' ? env?.mode : undefined) ?? 'production';
|
|
184
224
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
const [
|
|
226
|
+
{visualizer},
|
|
227
|
+
{sourceCode},
|
|
228
|
+
{css},
|
|
229
|
+
{rawAssets, staticAssets},
|
|
230
|
+
{magicModuleRequestRouterEntry},
|
|
231
|
+
nodePlugins,
|
|
232
|
+
] = await Promise.all([
|
|
233
|
+
import('rollup-plugin-visualizer'),
|
|
234
|
+
import('./features/source-code.ts'),
|
|
235
|
+
import('./features/css.ts'),
|
|
236
|
+
import('./features/assets.ts'),
|
|
237
|
+
import('./features/request-router.ts'),
|
|
238
|
+
getNodePlugins(),
|
|
239
|
+
]);
|
|
240
|
+
|
|
241
|
+
const plugins: Plugin[] = [
|
|
242
|
+
...nodePlugins,
|
|
243
|
+
sourceCode({mode}),
|
|
244
|
+
css({emit: false}),
|
|
245
|
+
rawAssets(),
|
|
246
|
+
staticAssets({emit: false}),
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
if (env) {
|
|
250
|
+
const {magicModuleEnv, replaceProcessEnv} = await import(
|
|
251
|
+
'./features/env.ts'
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (typeof env === 'boolean') {
|
|
255
|
+
plugins.push(replaceProcessEnv({mode}));
|
|
256
|
+
plugins.push(magicModuleEnv({mode}));
|
|
257
|
+
} else {
|
|
258
|
+
plugins.push(replaceProcessEnv({mode}));
|
|
259
|
+
plugins.push(magicModuleEnv({mode}));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (app) {
|
|
264
|
+
plugins.push(magicModuleAppComponent({entry: app}));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
plugins.push(magicModuleRequestRouterEntry());
|
|
268
|
+
plugins.push(magicModuleAppRequestRouter({entry}));
|
|
269
|
+
|
|
270
|
+
if (graphql) {
|
|
271
|
+
const {graphql} = await import('./features/graphql.ts');
|
|
272
|
+
plugins.push(graphql({manifest: false}));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (minify) {
|
|
276
|
+
const {minify} = await import('rollup-plugin-esbuild');
|
|
277
|
+
plugins.push(minify());
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
plugins.push(
|
|
281
|
+
visualizer({
|
|
282
|
+
template: 'treemap',
|
|
283
|
+
open: false,
|
|
284
|
+
brotliSize: true,
|
|
285
|
+
filename: path.resolve(`reports/bundle-visualizer.html`),
|
|
286
|
+
}),
|
|
287
|
+
);
|
|
224
288
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
entryFileNames: 'server.js',
|
|
234
|
-
};
|
|
289
|
+
return {
|
|
290
|
+
input: entry,
|
|
291
|
+
plugins,
|
|
292
|
+
output: {
|
|
293
|
+
// format: isESM ? 'esm' : 'systemjs',
|
|
294
|
+
format: 'esm',
|
|
295
|
+
dir: path.resolve(`build/server`),
|
|
296
|
+
entryFileNames: 'server.js',
|
|
235
297
|
},
|
|
236
|
-
} satisfies
|
|
298
|
+
} satisfies RollupOptions;
|
|
237
299
|
}
|
|
238
300
|
|
|
239
301
|
export function magicModuleAppComponent({entry}: {entry: string}) {
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import {readFile} from 'fs/promises';
|
|
3
|
+
import {createHash} from 'crypto';
|
|
4
|
+
|
|
5
|
+
import type {Plugin} from 'rollup';
|
|
6
|
+
import * as mime from 'mrmime';
|
|
7
|
+
|
|
8
|
+
const QUERY_PATTERN = /\?.*$/s;
|
|
9
|
+
const HASH_PATTERN = /#.*$/s;
|
|
10
|
+
const RAW_PATTERN = /(\?|&)raw(?:&|$)/;
|
|
11
|
+
|
|
12
|
+
const DEFAULT_INLINE_LIMIT = 4096;
|
|
13
|
+
const DEFAULT_OUTPUT_PATTERN = '[name].[hash].[ext]';
|
|
14
|
+
const DEFAULT_STATIC_ASSET_EXTENSIONS = [
|
|
15
|
+
// images
|
|
16
|
+
'.png',
|
|
17
|
+
'.jpg',
|
|
18
|
+
'.jpeg',
|
|
19
|
+
'.gif',
|
|
20
|
+
'.svg',
|
|
21
|
+
'.ico',
|
|
22
|
+
'.webp',
|
|
23
|
+
'.avif',
|
|
24
|
+
|
|
25
|
+
// media
|
|
26
|
+
'.mp4',
|
|
27
|
+
'.webm',
|
|
28
|
+
'.ogg',
|
|
29
|
+
'.mp3',
|
|
30
|
+
'.wav',
|
|
31
|
+
'.flac',
|
|
32
|
+
'.aac',
|
|
33
|
+
|
|
34
|
+
// fonts
|
|
35
|
+
'.woff',
|
|
36
|
+
'.woff2',
|
|
37
|
+
'.eot',
|
|
38
|
+
'.ttf',
|
|
39
|
+
'.otf',
|
|
40
|
+
|
|
41
|
+
// other
|
|
42
|
+
'.webmanifest',
|
|
43
|
+
'.pdf',
|
|
44
|
+
'.txt',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export function rawAssets(): Plugin {
|
|
48
|
+
return {
|
|
49
|
+
name: '@quilted/raw-assets',
|
|
50
|
+
async load(id) {
|
|
51
|
+
if (id.startsWith('\0') || !RAW_PATTERN.test(id)) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const moduleId = cleanModuleIdentifier(id);
|
|
56
|
+
|
|
57
|
+
this.addWatchFile(moduleId);
|
|
58
|
+
|
|
59
|
+
const file = await readFile(moduleId, {
|
|
60
|
+
encoding: 'utf-8',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return `export default ${JSON.stringify(file)}`;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function staticAssets({
|
|
69
|
+
emit = true,
|
|
70
|
+
baseURL = '/',
|
|
71
|
+
extensions = DEFAULT_STATIC_ASSET_EXTENSIONS,
|
|
72
|
+
inlineLimit = DEFAULT_INLINE_LIMIT,
|
|
73
|
+
outputPattern = DEFAULT_OUTPUT_PATTERN,
|
|
74
|
+
}: {
|
|
75
|
+
emit?: boolean;
|
|
76
|
+
baseURL?: string;
|
|
77
|
+
extensions?: readonly string[];
|
|
78
|
+
inlineLimit?: number;
|
|
79
|
+
outputPattern?: string;
|
|
80
|
+
} = {}) {
|
|
81
|
+
const assetCache = new Map<string, string>();
|
|
82
|
+
const assetMatcher = new RegExp(
|
|
83
|
+
`\\.(` +
|
|
84
|
+
extensions
|
|
85
|
+
.map((extension) =>
|
|
86
|
+
extension.startsWith('.') ? extension.slice(1) : extension,
|
|
87
|
+
)
|
|
88
|
+
.join('|') +
|
|
89
|
+
`)(\\?.*)?$`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
name: '@quilted/static-assets',
|
|
94
|
+
async load(id) {
|
|
95
|
+
if (id.startsWith('\0') || !assetMatcher.test(id)) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const cached = assetCache.get(id);
|
|
100
|
+
|
|
101
|
+
if (cached) {
|
|
102
|
+
return cached;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const file = cleanModuleIdentifier(id);
|
|
106
|
+
const content = await readFile(file);
|
|
107
|
+
|
|
108
|
+
let url: string;
|
|
109
|
+
|
|
110
|
+
if (!file.endsWith('.svg') && content.length < inlineLimit) {
|
|
111
|
+
// base64 inlined as a string
|
|
112
|
+
url = `data:${mime.lookup(file)};base64,${content.toString('base64')}`;
|
|
113
|
+
} else {
|
|
114
|
+
const contentHash = getHash(content);
|
|
115
|
+
|
|
116
|
+
const filename = assetFileNamesToFileName(
|
|
117
|
+
outputPattern,
|
|
118
|
+
file,
|
|
119
|
+
contentHash,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
url = `${
|
|
123
|
+
baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL
|
|
124
|
+
}/${filename}`;
|
|
125
|
+
|
|
126
|
+
if (emit) {
|
|
127
|
+
this.emitFile({
|
|
128
|
+
name: file,
|
|
129
|
+
type: 'asset',
|
|
130
|
+
fileName: filename,
|
|
131
|
+
source: content,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const source = `export default ${JSON.stringify(url)};`;
|
|
137
|
+
|
|
138
|
+
assetCache.set(id, source);
|
|
139
|
+
|
|
140
|
+
return source;
|
|
141
|
+
},
|
|
142
|
+
} satisfies Plugin;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function assetFileNamesToFileName(
|
|
146
|
+
pattern: string,
|
|
147
|
+
file: string,
|
|
148
|
+
contentHash: string,
|
|
149
|
+
): string {
|
|
150
|
+
const basename = path.basename(file);
|
|
151
|
+
|
|
152
|
+
const extname = path.extname(basename);
|
|
153
|
+
const ext = extname.substring(1);
|
|
154
|
+
const name = basename.slice(0, -extname.length);
|
|
155
|
+
const hash = contentHash;
|
|
156
|
+
|
|
157
|
+
return pattern.replace(/\[\w+\]/g, (placeholder) => {
|
|
158
|
+
switch (placeholder) {
|
|
159
|
+
case '[ext]':
|
|
160
|
+
return ext;
|
|
161
|
+
|
|
162
|
+
case '[extname]':
|
|
163
|
+
return extname;
|
|
164
|
+
|
|
165
|
+
case '[hash]':
|
|
166
|
+
return hash;
|
|
167
|
+
|
|
168
|
+
case '[name]':
|
|
169
|
+
return name;
|
|
170
|
+
}
|
|
171
|
+
throw new Error(
|
|
172
|
+
`invalid placeholder ${placeholder} in assetFileNames "${pattern}"`,
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getHash(text: Buffer | string): string {
|
|
178
|
+
return createHash('sha256').update(text).digest('hex').substring(0, 8);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function cleanModuleIdentifier(url: string) {
|
|
182
|
+
return url.replace(HASH_PATTERN, '').replace(QUERY_PATTERN, '');
|
|
183
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type {Plugin} from 'rollup';
|
|
2
|
+
|
|
3
|
+
export interface Options {
|
|
4
|
+
minify?: boolean;
|
|
5
|
+
emit?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const CSS_REGEX = /\.css$/;
|
|
9
|
+
const CSS_MODULE_REGEX = /\.module\.css$/;
|
|
10
|
+
|
|
11
|
+
export function css({minify = true, emit = true}: Options) {
|
|
12
|
+
const styles = new Map<string, string>();
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
name: '@quilted/css',
|
|
16
|
+
async transform(code, id) {
|
|
17
|
+
if (!CSS_REGEX.test(id)) return;
|
|
18
|
+
|
|
19
|
+
const {transform} = await import('lightningcss');
|
|
20
|
+
|
|
21
|
+
const transformed = transform({
|
|
22
|
+
filename: id,
|
|
23
|
+
code: new TextEncoder().encode(code),
|
|
24
|
+
cssModules: CSS_MODULE_REGEX.test(id),
|
|
25
|
+
minify: emit && minify,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
styles.set(id, new TextDecoder().decode(transformed.code));
|
|
29
|
+
|
|
30
|
+
const exports = transformed.exports
|
|
31
|
+
? Object.fromEntries(
|
|
32
|
+
Object.entries(transformed.exports).map(([key, exported]) => [
|
|
33
|
+
key,
|
|
34
|
+
exported.name,
|
|
35
|
+
]),
|
|
36
|
+
)
|
|
37
|
+
: undefined;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
code: exports
|
|
41
|
+
? `export default JSON.parse(${JSON.stringify(
|
|
42
|
+
JSON.stringify(exports),
|
|
43
|
+
)})`
|
|
44
|
+
: `export default undefined;`,
|
|
45
|
+
map: {mappings: ''},
|
|
46
|
+
moduleSideEffects: 'no-treeshake',
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
async renderChunk(_, chunk) {
|
|
50
|
+
if (!emit) return null;
|
|
51
|
+
|
|
52
|
+
let chunkCss = '';
|
|
53
|
+
|
|
54
|
+
for (const id of Object.keys(chunk.modules)) {
|
|
55
|
+
if (CSS_REGEX.test(id) && styles.has(id)) {
|
|
56
|
+
chunkCss += styles.get(id);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (chunkCss.length === 0) return null;
|
|
61
|
+
|
|
62
|
+
const code = chunkCss;
|
|
63
|
+
|
|
64
|
+
// if (minify) {
|
|
65
|
+
// const {default: CleanCSS} = await import('clean-css');
|
|
66
|
+
|
|
67
|
+
// const cleaner = new CleanCSS({
|
|
68
|
+
// rebase: false,
|
|
69
|
+
// });
|
|
70
|
+
|
|
71
|
+
// const minified = cleaner.minify(chunkCss);
|
|
72
|
+
|
|
73
|
+
// if (minified.errors.length > 0) {
|
|
74
|
+
// throw minified.errors[0];
|
|
75
|
+
// }
|
|
76
|
+
|
|
77
|
+
// code = minified.styles;
|
|
78
|
+
// }
|
|
79
|
+
|
|
80
|
+
const fileHandle = this.emitFile({
|
|
81
|
+
type: 'asset',
|
|
82
|
+
name: `${chunk.fileName.split('.')[0]}.css`,
|
|
83
|
+
source: code,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
chunk.imports.push(this.getFileName(fileHandle));
|
|
87
|
+
|
|
88
|
+
return null;
|
|
89
|
+
},
|
|
90
|
+
} satisfies Plugin;
|
|
91
|
+
}
|
|
@@ -3,10 +3,10 @@ import * as fs from 'fs';
|
|
|
3
3
|
|
|
4
4
|
import type {PluginContext} from 'rollup';
|
|
5
5
|
|
|
6
|
-
import {MAGIC_MODULE_ENV} from '
|
|
7
|
-
import {multiline} from '
|
|
8
|
-
import {smartReplace} from '
|
|
9
|
-
import {createMagicModulePlugin} from '
|
|
6
|
+
import {MAGIC_MODULE_ENV} from '../constants.ts';
|
|
7
|
+
import {multiline} from '../shared/strings.ts';
|
|
8
|
+
import {smartReplace} from '../shared/rollup.ts';
|
|
9
|
+
import {createMagicModulePlugin} from '../shared/magic-module.ts';
|
|
10
10
|
|
|
11
11
|
const EMPTY_PROCESS_ENV_OBJECT = {
|
|
12
12
|
'globalThis.process.env.': `({}).`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {MAGIC_MODULE_ENTRY, MAGIC_MODULE_REQUEST_ROUTER} from '
|
|
1
|
+
import {MAGIC_MODULE_ENTRY, MAGIC_MODULE_REQUEST_ROUTER} from '../constants.ts';
|
|
2
2
|
|
|
3
|
-
import {createMagicModulePlugin} from '
|
|
4
|
-
import {multiline} from '
|
|
3
|
+
import {createMagicModulePlugin} from '../shared/magic-module.ts';
|
|
4
|
+
import {multiline} from '../shared/strings.ts';
|
|
5
5
|
|
|
6
6
|
export function magicModuleRequestRouterEntry({
|
|
7
7
|
host,
|
|
@@ -12,6 +12,7 @@ export function sourceCode({
|
|
|
12
12
|
targets?: string[];
|
|
13
13
|
}) {
|
|
14
14
|
return babel({
|
|
15
|
+
envName: mode,
|
|
15
16
|
configFile: false,
|
|
16
17
|
babelrc: false,
|
|
17
18
|
presets: [
|
|
@@ -60,5 +61,7 @@ export function sourceCode({
|
|
|
60
61
|
exclude: 'node_modules/**',
|
|
61
62
|
babelHelpers: 'bundled',
|
|
62
63
|
skipPreflightCheck: true,
|
|
64
|
+
// Babel doesn’t like this option being set to `undefined`.
|
|
65
|
+
...(targets ? {targets} : {}),
|
|
63
66
|
});
|
|
64
67
|
}
|