@remix-run/assets 0.0.0 → 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.
- package/LICENSE +21 -0
- package/README.md +325 -2
- package/dist/assets.d.ts +3 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +1 -0
- package/dist/lib/access.d.ts +10 -0
- package/dist/lib/access.d.ts.map +1 -0
- package/dist/lib/access.js +14 -0
- package/dist/lib/asset-server.d.ts +139 -0
- package/dist/lib/asset-server.d.ts.map +1 -0
- package/dist/lib/asset-server.js +338 -0
- package/dist/lib/compilation-error.d.ts +33 -0
- package/dist/lib/compilation-error.d.ts.map +1 -0
- package/dist/lib/compilation-error.js +32 -0
- package/dist/lib/file-matcher.d.ts +6 -0
- package/dist/lib/file-matcher.d.ts.map +1 -0
- package/dist/lib/file-matcher.js +44 -0
- package/dist/lib/fingerprint.d.ts +12 -0
- package/dist/lib/fingerprint.d.ts.map +1 -0
- package/dist/lib/fingerprint.js +49 -0
- package/dist/lib/module-store.d.ts +41 -0
- package/dist/lib/module-store.d.ts.map +1 -0
- package/dist/lib/module-store.js +230 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +50 -0
- package/dist/lib/routes.d.ts +13 -0
- package/dist/lib/routes.d.ts.map +1 -0
- package/dist/lib/routes.js +94 -0
- package/dist/lib/scripts/cjs-check.d.ts +3 -0
- package/dist/lib/scripts/cjs-check.d.ts.map +1 -0
- package/dist/lib/scripts/cjs-check.js +398 -0
- package/dist/lib/scripts/compiler.d.ts +62 -0
- package/dist/lib/scripts/compiler.d.ts.map +1 -0
- package/dist/lib/scripts/compiler.js +439 -0
- package/dist/lib/scripts/emit.d.ts +25 -0
- package/dist/lib/scripts/emit.d.ts.map +1 -0
- package/dist/lib/scripts/emit.js +63 -0
- package/dist/lib/scripts/resolve.d.ts +50 -0
- package/dist/lib/scripts/resolve.d.ts.map +1 -0
- package/dist/lib/scripts/resolve.js +236 -0
- package/dist/lib/scripts/transform.d.ts +64 -0
- package/dist/lib/scripts/transform.d.ts.map +1 -0
- package/dist/lib/scripts/transform.js +373 -0
- package/dist/lib/source-maps.d.ts +4 -0
- package/dist/lib/source-maps.d.ts.map +1 -0
- package/dist/lib/source-maps.js +62 -0
- package/dist/lib/styles/compiler.d.ts +52 -0
- package/dist/lib/styles/compiler.d.ts.map +1 -0
- package/dist/lib/styles/compiler.js +272 -0
- package/dist/lib/styles/emit.d.ts +25 -0
- package/dist/lib/styles/emit.d.ts.map +1 -0
- package/dist/lib/styles/emit.js +78 -0
- package/dist/lib/styles/resolve.d.ts +48 -0
- package/dist/lib/styles/resolve.d.ts.map +1 -0
- package/dist/lib/styles/resolve.js +188 -0
- package/dist/lib/styles/transform.d.ts +47 -0
- package/dist/lib/styles/transform.d.ts.map +1 -0
- package/dist/lib/styles/transform.js +131 -0
- package/dist/lib/target.d.ts +21 -0
- package/dist/lib/target.d.ts.map +1 -0
- package/dist/lib/target.js +127 -0
- package/dist/lib/watch.d.ts +22 -0
- package/dist/lib/watch.d.ts.map +1 -0
- package/dist/lib/watch.js +96 -0
- package/package.json +55 -12
- package/src/assets.ts +2 -0
- package/src/lib/access.ts +24 -0
- package/src/lib/asset-server.ts +537 -0
- package/src/lib/compilation-error.ts +61 -0
- package/src/lib/file-matcher.ts +63 -0
- package/src/lib/fingerprint.ts +65 -0
- package/src/lib/module-store.ts +340 -0
- package/src/lib/paths.ts +66 -0
- package/src/lib/routes.ts +164 -0
- package/src/lib/scripts/cjs-check.ts +476 -0
- package/src/lib/scripts/compiler.ts +640 -0
- package/src/lib/scripts/emit.ts +122 -0
- package/src/lib/scripts/resolve.ts +433 -0
- package/src/lib/scripts/transform.ts +609 -0
- package/src/lib/source-maps.ts +75 -0
- package/src/lib/styles/compiler.ts +400 -0
- package/src/lib/styles/emit.ts +137 -0
- package/src/lib/styles/resolve.ts +316 -0
- package/src/lib/styles/transform.ts +226 -0
- package/src/lib/target.ts +196 -0
- package/src/lib/watch.ts +136 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Shopify Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,326 @@
|
|
|
1
|
-
#
|
|
1
|
+
# assets
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fetch-based server for compiling browser JS/TS and CSS assets on demand.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **On-Demand Compilation** - Compile browser scripts and styles on demand
|
|
8
|
+
- **Custom File Mapping** - Define patterns for mapping public URLs to file paths on disk
|
|
9
|
+
- **Access Control** - Control exactly which files can be served with allow and deny rules
|
|
10
|
+
- **Preloads** - Generate preload URLs for scripts and styles based on imports
|
|
11
|
+
- **Caching** - Conservative caching by default with stable URLs, ETags, and revalidation
|
|
12
|
+
- **Optional Fingerprinting** - Source-based fingerprinted URLs for long-lived browser caching
|
|
13
|
+
- **Source Maps** - Serve inline or external sourcemaps
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm i remix
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Use `createAssetServer` to serve browser JS/TS and CSS assets from a URL namespace in your app.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createRouter } from 'remix/fetch-router'
|
|
27
|
+
import { createAssetServer } from 'remix/assets'
|
|
28
|
+
|
|
29
|
+
let assetServer = createAssetServer({
|
|
30
|
+
fileMap: {
|
|
31
|
+
'/assets/app/*path': 'app/*path',
|
|
32
|
+
'/assets/npm/*path': 'node_modules/*path',
|
|
33
|
+
},
|
|
34
|
+
allow: ['app/assets/**', 'node_modules/**'],
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
let router = createRouter()
|
|
38
|
+
|
|
39
|
+
router.get('/assets/*', ({ request }) => {
|
|
40
|
+
return assetServer.fetch(request)
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This example gives you an `/assets/*` endpoint that serves compiled browser assets from `app/assets` and `node_modules`.
|
|
45
|
+
|
|
46
|
+
## Root Directory
|
|
47
|
+
|
|
48
|
+
Use `rootDir` to specify the root directory of the asset server, which is used to resolve relative file paths. Defaults to `process.cwd()`.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import * as path from 'node:path'
|
|
52
|
+
import { createAssetServer } from 'remix/assets'
|
|
53
|
+
|
|
54
|
+
let assetServer = createAssetServer({
|
|
55
|
+
rootDir: path.resolve(import.meta.dirname, '..'),
|
|
56
|
+
fileMap: {
|
|
57
|
+
'/assets/app/*path': 'app/*path',
|
|
58
|
+
'/assets/npm/*path': 'node_modules/*path',
|
|
59
|
+
},
|
|
60
|
+
allow: ['app/assets/**', 'node_modules/**'],
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Access Control
|
|
65
|
+
|
|
66
|
+
You must provide an `allow` list to specify which files are allowed to be served. `deny` is optional and takes precedence over `allow`.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createAssetServer } from 'remix/assets'
|
|
70
|
+
|
|
71
|
+
let assetServer = createAssetServer({
|
|
72
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
73
|
+
allow: ['app/assets/**'],
|
|
74
|
+
deny: ['app/**/*.server.*'],
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Rules for `allow` and `deny` are file paths or globs. Relative values are resolved from `rootDir`. Absolute file paths match exactly, and absolute directory paths also match their descendants.
|
|
79
|
+
|
|
80
|
+
## File Map
|
|
81
|
+
|
|
82
|
+
Use `fileMap` to map public URLs to file paths on disk. The keys are public URL patterns, and the values are root-relative file path patterns.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { createAssetServer } from 'remix/assets'
|
|
86
|
+
|
|
87
|
+
let assetServer = createAssetServer({
|
|
88
|
+
fileMap: {
|
|
89
|
+
'/assets/app/*path': 'app/*path',
|
|
90
|
+
'/assets/packages/*path': '../packages/*path',
|
|
91
|
+
},
|
|
92
|
+
allow: ['app/assets/**', '../packages/**'],
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`fileMap` entries use [`route-pattern`](https://github.com/remix-run/remix/tree/main/packages/route-pattern) syntax for both URL and file patterns. Wildcards must be named, and the same params must appear in both patterns so imports can be rewritten back to public URLs.
|
|
97
|
+
|
|
98
|
+
### File watching
|
|
99
|
+
|
|
100
|
+
The file system is watched by default so source changes are picked up without requiring a server restart.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { createAssetServer } from 'remix/assets'
|
|
104
|
+
|
|
105
|
+
let assetServer = createAssetServer({
|
|
106
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
107
|
+
allow: ['app/assets/**', 'app/node_modules/**'],
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
When finished with the asset server, call `await assetServer.close()` to clean up the file watcher.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
await assetServer.close()
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
You can disable file watching if the files on disk won't change, or if watching is managed at a higher level (e.g. Node's `--watch` flag).
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { createAssetServer } from 'remix/assets'
|
|
121
|
+
|
|
122
|
+
let assetServer = createAssetServer({
|
|
123
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
124
|
+
allow: ['app/assets/**', 'app/node_modules/**'],
|
|
125
|
+
watch: false,
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
You can optionally provide an array of glob patterns to the `watch.ignore` option:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { createAssetServer } from 'remix/assets'
|
|
133
|
+
|
|
134
|
+
let assetServer = createAssetServer({
|
|
135
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
136
|
+
allow: ['app/assets/**', 'app/node_modules/**'],
|
|
137
|
+
watch: {
|
|
138
|
+
ignore: ['**/node_modules/**'],
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Hrefs
|
|
144
|
+
|
|
145
|
+
Use `assetServer.getHref()` when you need the public URL for a served asset. You can provide a root-relative or absolute file path, or a `file://` URL.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
let src = await assetServer.getHref('app/assets/entry.tsx')
|
|
149
|
+
// '/assets/app/assets/entry.tsx'
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Preloads
|
|
153
|
+
|
|
154
|
+
Use `assetServer.getPreloads()` when rendering HTML so you can turn the returned URLs into `<link rel="modulepreload">`, stylesheet preload tags, or `Link` headers for one or more assets and their dependencies. You can provide root-relative or absolute file paths, or `file://` URLs.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
let preloads = await assetServer.getPreloads(['app/assets/entry.tsx', 'app/assets/search.tsx'])
|
|
158
|
+
// [
|
|
159
|
+
// '/assets/app/assets/entry.tsx',
|
|
160
|
+
// '/assets/app/assets/search.tsx',
|
|
161
|
+
// '/assets/app/assets/utils.ts',
|
|
162
|
+
// '/assets/npm/@remix-run/ui/index.js',
|
|
163
|
+
// ...etc
|
|
164
|
+
// ]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Fingerprinting
|
|
168
|
+
|
|
169
|
+
By default, assets are served at stable URLs with ETags and `Cache-Control: no-cache`. Responses are cached for the lifetime of the asset server instance.
|
|
170
|
+
|
|
171
|
+
If you want clients to cache assets aggressively without revalidation, you can opt into source-based fingerprinting.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { createAssetServer } from 'remix/assets'
|
|
175
|
+
|
|
176
|
+
let assetServer = createAssetServer({
|
|
177
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
178
|
+
allow: ['app/assets/**'],
|
|
179
|
+
watch: false,
|
|
180
|
+
fingerprint: {
|
|
181
|
+
buildId: process.env.GITHUB_SHA,
|
|
182
|
+
},
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
When fingerprinting is enabled, assets use a `.@<fingerprint>` segment before the file extension and are served with `Cache-Control: public, max-age=31536000, immutable`.
|
|
187
|
+
|
|
188
|
+
Source fingerprints are based on the original file contents and the build ID. The build ID must change for each deployment so that fingerprinted assets are invalidated together. This fingerprinting strategy assumes that files on disk won't change, so fingerprinting requires `watch: false`.
|
|
189
|
+
|
|
190
|
+
## Target
|
|
191
|
+
|
|
192
|
+
Use `target` to lower emitted syntax to a specific browser support policy and/or ECMAScript version.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { createAssetServer } from 'remix/assets'
|
|
196
|
+
|
|
197
|
+
let assetServer = createAssetServer({
|
|
198
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
199
|
+
allow: ['app/assets/**'],
|
|
200
|
+
target: {
|
|
201
|
+
chrome: '109',
|
|
202
|
+
ios: '15.6',
|
|
203
|
+
es: '2020',
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Supported target options are `chrome`, `firefox`, `safari`, `edge`, `opera`, `ios`, `samsung`, and `es` (ECMAScript version).
|
|
209
|
+
|
|
210
|
+
### Source Maps
|
|
211
|
+
|
|
212
|
+
Enable sourcemaps with either `'external'` or `'inline'` using `sourceMaps`:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { createAssetServer } from 'remix/assets'
|
|
216
|
+
|
|
217
|
+
let assetServer = createAssetServer({
|
|
218
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
219
|
+
allow: ['app/assets/**'],
|
|
220
|
+
sourceMaps: 'external',
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
By default, sourcemap `sources` use URLs so they're presented alongside the compiled output in your browser's developer tools. You can also use file system paths instead with `sourceMapSourcePaths`:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { createAssetServer } from 'remix/assets'
|
|
228
|
+
|
|
229
|
+
let assetServer = createAssetServer({
|
|
230
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
231
|
+
allow: ['app/assets/**'],
|
|
232
|
+
sourceMaps: 'inline',
|
|
233
|
+
sourceMapSourcePaths: 'absolute',
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Minification
|
|
238
|
+
|
|
239
|
+
Enable minification with `minify`:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { createAssetServer } from 'remix/assets'
|
|
243
|
+
|
|
244
|
+
let assetServer = createAssetServer({
|
|
245
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
246
|
+
allow: ['app/assets/**'],
|
|
247
|
+
minify: true,
|
|
248
|
+
})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Script Options
|
|
252
|
+
|
|
253
|
+
### Define
|
|
254
|
+
|
|
255
|
+
Use `scripts.define` to replace global identifiers with constant expressions.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { createAssetServer } from 'remix/assets'
|
|
259
|
+
|
|
260
|
+
let assetServer = createAssetServer({
|
|
261
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
262
|
+
allow: ['app/assets/**', 'app/node_modules/**'],
|
|
263
|
+
scripts: {
|
|
264
|
+
define: {
|
|
265
|
+
'process.env.NODE_ENV': '"production"',
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
})
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Values are injected exactly as defined, so string literals must include their own quotes, e.g. `process.env.NODE_ENV` must be `"production"` rather than `production`.
|
|
272
|
+
|
|
273
|
+
### External Imports
|
|
274
|
+
|
|
275
|
+
Use `scripts.external` to leave specific import specifiers unchanged by providing an array of specifiers.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { createAssetServer } from 'remix/assets'
|
|
279
|
+
|
|
280
|
+
let assetServer = createAssetServer({
|
|
281
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
282
|
+
allow: ['app/assets/**'],
|
|
283
|
+
scripts: {
|
|
284
|
+
external: ['my-external-import'],
|
|
285
|
+
},
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## CSS Imports
|
|
290
|
+
|
|
291
|
+
Relative CSS `@import` rules are rewritten to asset server URLs. External `@import` URLs are left unchanged automatically. `url()` references are preserved as authored.
|
|
292
|
+
|
|
293
|
+
```css
|
|
294
|
+
/* Rewritten to asset server URL: */
|
|
295
|
+
@import './reset.css';
|
|
296
|
+
/* External URL: */
|
|
297
|
+
@import 'https://fonts.googleapis.com/css2?family=Inter';
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Error Handling
|
|
301
|
+
|
|
302
|
+
Use `onError` to report unexpected compilation failures and/or return a custom response.
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
import { createAssetServer } from 'remix/assets'
|
|
306
|
+
|
|
307
|
+
let assetServer = createAssetServer({
|
|
308
|
+
fileMap: { '/assets/app/*path': 'app/*path' },
|
|
309
|
+
allow: ['app/assets/**'],
|
|
310
|
+
onError(error) {
|
|
311
|
+
console.error('Failed to build client assets', error)
|
|
312
|
+
return new Response('Client asset build failed', { status: 500 })
|
|
313
|
+
},
|
|
314
|
+
})
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
If `onError` returns nothing, the asset server responds with the default `500 Internal Server Error` response.
|
|
318
|
+
|
|
319
|
+
## Related Packages
|
|
320
|
+
|
|
321
|
+
- [`fetch-router`](https://github.com/remix-run/remix/tree/main/packages/fetch-router) - A Fetch-based router that pairs naturally with `assets`
|
|
322
|
+
- [`route-pattern`](https://github.com/remix-run/remix/tree/main/packages/route-pattern) - Route-pattern syntax for URL and route file matching
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
|
package/dist/assets.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA"}
|
package/dist/assets.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createAssetServer } from "./lib/asset-server.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type AccessPolicy = {
|
|
2
|
+
isAllowed(filePath: string): boolean;
|
|
3
|
+
};
|
|
4
|
+
export declare function createAccessPolicy(options: {
|
|
5
|
+
allow: readonly string[];
|
|
6
|
+
deny?: readonly string[];
|
|
7
|
+
rootDir: string;
|
|
8
|
+
}): AccessPolicy;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/lib/access.ts"],"names":[],"mappings":"AAEA,KAAK,YAAY,GAAG;IAClB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;CACrC,CAAA;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,YAAY,CAaf"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createFileMatcher } from "./file-matcher.js";
|
|
2
|
+
export function createAccessPolicy(options) {
|
|
3
|
+
let allowMatchers = options.allow.map((pattern) => createFileMatcher(pattern, options.rootDir));
|
|
4
|
+
let denyMatchers = (options.deny ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir));
|
|
5
|
+
return {
|
|
6
|
+
isAllowed(filePath) {
|
|
7
|
+
if (!allowMatchers.some((matcher) => matcher(filePath)))
|
|
8
|
+
return false;
|
|
9
|
+
if (denyMatchers.length > 0 && denyMatchers.some((matcher) => matcher(filePath)))
|
|
10
|
+
return false;
|
|
11
|
+
return true;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { AssetTarget } from './target.ts';
|
|
2
|
+
import type { ChokidarWatcher } from './watch.ts';
|
|
3
|
+
interface AssetServerWatchOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Ignore matching glob patterns or file paths. Relative values are resolved
|
|
6
|
+
* from `rootDir`.
|
|
7
|
+
*/
|
|
8
|
+
ignore?: readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* Use polling instead of native filesystem events. Defaults to `false`.
|
|
11
|
+
*/
|
|
12
|
+
poll?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Polling interval in milliseconds when `poll` is enabled. Defaults to `100`.
|
|
15
|
+
*/
|
|
16
|
+
pollInterval?: number;
|
|
17
|
+
}
|
|
18
|
+
interface FingerprintOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Per-build invalidation token that must change whenever fingerprinted asset URLs
|
|
21
|
+
* should be invalidated together.
|
|
22
|
+
*/
|
|
23
|
+
buildId: string;
|
|
24
|
+
}
|
|
25
|
+
type AssetSourceMaps = 'inline' | 'external';
|
|
26
|
+
type AssetSourceMapSourcePaths = 'url' | 'absolute';
|
|
27
|
+
interface AssetServerScriptOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Replace global expressions with constant values during transform, e.g.
|
|
30
|
+
* `{ 'process.env.NODE_ENV': '"production"' }`
|
|
31
|
+
*/
|
|
32
|
+
define?: Record<string, string>;
|
|
33
|
+
/** Import specifiers to leave unrewritten (CDN URLs, import map entries, etc.) */
|
|
34
|
+
external?: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface AssetServerOptions {
|
|
37
|
+
/** File patterns keyed by public URL patterns. */
|
|
38
|
+
fileMap: Readonly<Record<string, string>>;
|
|
39
|
+
/**
|
|
40
|
+
* Root directory used to resolve relative file paths. Defaults to `process.cwd()`.
|
|
41
|
+
*/
|
|
42
|
+
rootDir?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Glob patterns or file paths that are allowed to be served. Relative values are resolved from `rootDir`.
|
|
45
|
+
*/
|
|
46
|
+
allow: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* Glob patterns or file paths that are denied from being served. Relative values are resolved from `rootDir`.
|
|
49
|
+
*/
|
|
50
|
+
deny?: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Controls optional source-based URL fingerprinting for rewritten asset URLs.
|
|
53
|
+
*
|
|
54
|
+
* When omitted, all served assets use stable non-fingerprinted URLs with `Cache-Control: no-cache`.
|
|
55
|
+
* Cannot be used together with active watch mode. Set `watch: false` when fingerprinting.
|
|
56
|
+
*/
|
|
57
|
+
fingerprint?: FingerprintOptions;
|
|
58
|
+
/**
|
|
59
|
+
* Shared compatibility target for scripts and styles. Browser targets apply to both
|
|
60
|
+
* pipelines, and `es` only affects scripts.
|
|
61
|
+
*/
|
|
62
|
+
target?: AssetTarget;
|
|
63
|
+
/**
|
|
64
|
+
* Source map mode for scripts and styles.
|
|
65
|
+
* - `'external'`: serve source maps as separate `.map` files
|
|
66
|
+
* - `'inline'`: embed source maps as a base64 data URL in the compiled asset
|
|
67
|
+
*/
|
|
68
|
+
sourceMaps?: AssetSourceMaps;
|
|
69
|
+
/**
|
|
70
|
+
* Source path strategy for source map `sources`.
|
|
71
|
+
* - `'url'` (default): use the stable server path (e.g. `'/assets/app/entry.ts'`)
|
|
72
|
+
* - `'absolute'`: use the original filesystem path on disk
|
|
73
|
+
*/
|
|
74
|
+
sourceMapSourcePaths?: AssetSourceMapSourcePaths;
|
|
75
|
+
/**
|
|
76
|
+
* Minification setting for emitted scripts and styles.
|
|
77
|
+
*/
|
|
78
|
+
minify?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Script-only configuration.
|
|
81
|
+
*/
|
|
82
|
+
scripts?: AssetServerScriptOptions;
|
|
83
|
+
/**
|
|
84
|
+
* Enable filesystem-backed cache invalidation for long-lived server instances.
|
|
85
|
+
* Enabled by default. Pass `true` to use the default watcher options, an options
|
|
86
|
+
* object to customize watcher behavior, or `false` to disable watching.
|
|
87
|
+
*/
|
|
88
|
+
watch?: boolean | AssetServerWatchOptions;
|
|
89
|
+
/**
|
|
90
|
+
* Handles unexpected request-time compilation errors. Return a `Response` to override the
|
|
91
|
+
* default `500 Internal Server Error` response, or return nothing to use the default.
|
|
92
|
+
*/
|
|
93
|
+
onError?: (error: unknown) => void | Response | Promise<void | Response>;
|
|
94
|
+
}
|
|
95
|
+
export interface AssetServer {
|
|
96
|
+
/**
|
|
97
|
+
* Serves a script or style request. Returns `Response | null` — null means the request
|
|
98
|
+
* was not handled by this server, letting the router fall through to a 404.
|
|
99
|
+
*/
|
|
100
|
+
fetch(request: Request): Promise<Response | null>;
|
|
101
|
+
/**
|
|
102
|
+
* Returns the request href for a served asset file.
|
|
103
|
+
*/
|
|
104
|
+
getHref(filePath: string): Promise<string>;
|
|
105
|
+
/**
|
|
106
|
+
* Returns preload URLs for one or more served asset files, ordered shallowest-first.
|
|
107
|
+
*/
|
|
108
|
+
getPreloads(filePath: string | readonly string[]): Promise<string[]>;
|
|
109
|
+
/**
|
|
110
|
+
* Closes any watcher resources owned by this server instance.
|
|
111
|
+
*/
|
|
112
|
+
close(): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
export declare function getInternalChokidarWatcher(assetServer: AssetServer): ChokidarWatcher | undefined;
|
|
115
|
+
export declare function getInternalWatchTargets(assetServer: AssetServer): readonly string[];
|
|
116
|
+
/**
|
|
117
|
+
* Create an asset server instance
|
|
118
|
+
*
|
|
119
|
+
* Compiles TypeScript/JavaScript scripts and CSS styles on demand with optional
|
|
120
|
+
* source-based URL fingerprinting, caching, and configurable file mapping.
|
|
121
|
+
*
|
|
122
|
+
* @param options Server configuration
|
|
123
|
+
* @returns A {@link AssetServer} with `fetch()`, `getHref()`, and `getPreloads()` methods
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* let assetServer = createAssetServer({
|
|
128
|
+
* fileMap: {
|
|
129
|
+
* '/assets/app/*path': 'app/*path',
|
|
130
|
+
* },
|
|
131
|
+
* allow: ['app/**'],
|
|
132
|
+
* })
|
|
133
|
+
*
|
|
134
|
+
* route('/assets/*path', ({ request }) => assetServer.fetch(request))
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare function createAssetServer(options: AssetServerOptions): AssetServer;
|
|
138
|
+
export {};
|
|
139
|
+
//# sourceMappingURL=asset-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-server.d.ts","sourceRoot":"","sources":["../../src/lib/asset-server.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAA6C,MAAM,aAAa,CAAA;AAEzF,OAAO,KAAK,EAAsB,eAAe,EAAE,MAAM,YAAY,CAAA;AAErE,UAAU,uBAAuB;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,UAAU,kBAAkB;IAC1B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,KAAK,eAAe,GAAG,QAAQ,GAAG,UAAU,CAAA;AAC5C,KAAK,yBAAyB,GAAG,KAAK,GAAG,UAAU,CAAA;AAEnD,UAAU,wBAAwB;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAID,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,yBAAyB,CAAA;IAChD;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,wBAAwB,CAAA;IAClC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,uBAAuB,CAAA;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAA;CACzE;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;IACjD;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1C;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACpE;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAuBD,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,eAAe,GAAG,SAAS,CAEhG;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,MAAM,EAAE,CAEnF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAqN1E"}
|