@remix-run/assets 0.5.0 → 0.7.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/README.md +185 -104
- package/dist/assets.d.ts +4 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/lib/access.d.ts +29 -2
- package/dist/lib/access.d.ts.map +1 -1
- package/dist/lib/access.js +52 -26
- package/dist/lib/asset-server.d.ts +61 -25
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +127 -55
- package/dist/lib/compilation-error.d.ts +1 -1
- package/dist/lib/compilation-error.d.ts.map +1 -1
- package/dist/lib/files/compiler.d.ts +1 -1
- package/dist/lib/files/compiler.d.ts.map +1 -1
- package/dist/lib/files/compiler.js +28 -31
- package/dist/lib/files/config.d.ts +6 -0
- package/dist/lib/files/config.d.ts.map +1 -1
- package/dist/lib/files/config.js +9 -0
- package/dist/lib/fingerprint.d.ts +0 -4
- package/dist/lib/fingerprint.d.ts.map +1 -1
- package/dist/lib/fingerprint.js +0 -4
- package/dist/lib/hmr.d.ts +7 -0
- package/dist/lib/hmr.d.ts.map +1 -1
- package/dist/lib/hmr.js +198 -25
- package/dist/lib/injected-packages.d.ts +3 -2
- package/dist/lib/injected-packages.d.ts.map +1 -1
- package/dist/lib/injected-packages.js +11 -8
- package/dist/lib/inspection.d.ts +39 -0
- package/dist/lib/inspection.d.ts.map +1 -0
- package/dist/lib/inspection.js +160 -0
- package/dist/lib/routes.d.ts +12 -3
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +124 -80
- package/dist/lib/scripts/compiler.d.ts +8 -2
- package/dist/lib/scripts/compiler.d.ts.map +1 -1
- package/dist/lib/scripts/compiler.js +188 -38
- package/dist/lib/scripts/emit.d.ts +2 -1
- package/dist/lib/scripts/emit.d.ts.map +1 -1
- package/dist/lib/scripts/emit.js +25 -16
- package/dist/lib/scripts/resolve.d.ts +7 -1
- package/dist/lib/scripts/resolve.d.ts.map +1 -1
- package/dist/lib/scripts/resolve.js +119 -12
- package/dist/lib/scripts/specifiers.d.ts +2 -0
- package/dist/lib/scripts/specifiers.d.ts.map +1 -0
- package/dist/lib/scripts/specifiers.js +9 -0
- package/dist/lib/scripts/transform.d.ts +2 -3
- package/dist/lib/scripts/transform.d.ts.map +1 -1
- package/dist/lib/scripts/transform.js +4 -18
- package/dist/lib/styles/compiler.d.ts +0 -1
- package/dist/lib/styles/compiler.d.ts.map +1 -1
- package/dist/lib/styles/compiler.js +105 -25
- package/dist/lib/styles/emit.d.ts +2 -1
- package/dist/lib/styles/emit.d.ts.map +1 -1
- package/dist/lib/styles/emit.js +12 -10
- package/dist/lib/styles/resolve.d.ts +0 -1
- package/dist/lib/styles/resolve.d.ts.map +1 -1
- package/dist/lib/styles/resolve.js +8 -9
- package/dist/lib/styles/transform.d.ts +0 -2
- package/dist/lib/styles/transform.d.ts.map +1 -1
- package/dist/lib/styles/transform.js +2 -9
- package/dist/lib/virtual-store.d.ts +8 -0
- package/dist/lib/virtual-store.d.ts.map +1 -0
- package/dist/lib/virtual-store.js +100 -0
- package/package.json +6 -6
- package/src/assets.ts +9 -1
- package/src/lib/access.ts +83 -30
- package/src/lib/asset-server.ts +224 -94
- package/src/lib/compilation-error.ts +4 -3
- package/src/lib/files/compiler.ts +32 -42
- package/src/lib/files/config.ts +17 -0
- package/src/lib/fingerprint.ts +0 -9
- package/src/lib/hmr.ts +210 -26
- package/src/lib/injected-packages.ts +16 -10
- package/src/lib/inspection.ts +229 -0
- package/src/lib/routes.ts +158 -126
- package/src/lib/scripts/compiler.ts +240 -54
- package/src/lib/scripts/emit.ts +34 -19
- package/src/lib/scripts/resolve.ts +175 -13
- package/src/lib/scripts/specifiers.ts +11 -0
- package/src/lib/scripts/transform.ts +6 -25
- package/src/lib/styles/compiler.ts +137 -39
- package/src/lib/styles/emit.ts +18 -13
- package/src/lib/styles/resolve.ts +8 -10
- package/src/lib/styles/transform.ts +2 -12
- package/src/lib/virtual-store.ts +124 -0
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@ Fetch-based server for compiling browser assets on demand.
|
|
|
6
6
|
|
|
7
7
|
- **On-Demand Compilation** - Compile browser scripts and styles on demand
|
|
8
8
|
- **File Serving** - Serve configured file assets like images and fonts with optional transforms
|
|
9
|
-
- **Custom File Mapping** - Define patterns for mapping public URLs to file paths on disk
|
|
10
9
|
- **Access Control** - Control exactly which files and packages can be served
|
|
11
10
|
- **Preloads** - Generate preload URLs for scripts and styles based on imports
|
|
11
|
+
- **Inspection** - List browser-reachable assets and explain URL-to-file mappings
|
|
12
12
|
- **Caching** - Conservative caching by default with stable URLs, ETags, and revalidation
|
|
13
|
-
- **Optional Fingerprinting** -
|
|
13
|
+
- **Optional Fingerprinting** - Content-based fingerprinted URLs for long-lived browser caching
|
|
14
14
|
- **Source Maps** - Serve inline or external sourcemaps
|
|
15
15
|
- **Hot Module Reloading** - Handle live code updates in development
|
|
16
16
|
- **Script Loaders** - Post-process compiled JavaScript with Node-compatible loaders
|
|
@@ -21,6 +21,12 @@ Fetch-based server for compiling browser assets on demand.
|
|
|
21
21
|
npm i remix
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
The optional image transform examples also use Sharp:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm i sharp
|
|
28
|
+
```
|
|
29
|
+
|
|
24
30
|
## Usage
|
|
25
31
|
|
|
26
32
|
Use `createAssetServer` to serve browser assets from a URL namespace in your app.
|
|
@@ -31,10 +37,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
31
37
|
|
|
32
38
|
let assetServer = createAssetServer({
|
|
33
39
|
basePath: '/assets',
|
|
34
|
-
fileMap: {
|
|
35
|
-
'/app/*path': 'app/*path',
|
|
36
|
-
'/npm/*path': 'node_modules/*path',
|
|
37
|
-
},
|
|
38
40
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
39
41
|
allowPackages: ['remix'],
|
|
40
42
|
files: {
|
|
@@ -51,6 +53,64 @@ router.get('/assets/*', ({ request }) => {
|
|
|
51
53
|
|
|
52
54
|
This example gives you an `/assets/*` endpoint that serves compiled browser source from `public/` directories throughout `app/` and from the `remix` package.
|
|
53
55
|
|
|
56
|
+
## Shared Configuration
|
|
57
|
+
|
|
58
|
+
Keep JSON-compatible asset mapping, access, and file-type settings in `remix.json` so the running
|
|
59
|
+
server and Remix CLI use the same configuration:
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
{
|
|
63
|
+
"$schema": "./node_modules/remix/schema/remix.json",
|
|
64
|
+
"assets": {
|
|
65
|
+
"basePath": "/assets",
|
|
66
|
+
"mounts": {
|
|
67
|
+
"app": "app",
|
|
68
|
+
"npm": "node_modules",
|
|
69
|
+
},
|
|
70
|
+
"allowFiles": ["app/routes.ts", "app/**/public/**"],
|
|
71
|
+
"allowPackages": ["remix"],
|
|
72
|
+
"denyFiles": ["app/**/*.test.*"],
|
|
73
|
+
"files": {
|
|
74
|
+
"extensions": [".svg", ".png", ".jpg", ".woff2"],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Load it from application code and add runtime-only behavior there:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { createAssetServer, defineFileTransform } from 'remix/assets'
|
|
84
|
+
import { loadConfig } from 'remix/cli'
|
|
85
|
+
import sharp from 'sharp'
|
|
86
|
+
|
|
87
|
+
let config = await loadConfig(import.meta.dirname)
|
|
88
|
+
if (config.assets === undefined) throw new Error('Missing assets configuration')
|
|
89
|
+
if (config.assets.files === undefined) throw new Error('Missing asset file configuration')
|
|
90
|
+
|
|
91
|
+
let assetServer = createAssetServer({
|
|
92
|
+
...config.assets,
|
|
93
|
+
files: {
|
|
94
|
+
...config.assets.files,
|
|
95
|
+
transforms: {
|
|
96
|
+
webp: defineFileTransform({
|
|
97
|
+
extensions: ['.png', '.jpg'],
|
|
98
|
+
async transform(bytes) {
|
|
99
|
+
return {
|
|
100
|
+
content: await sharp(bytes).webp({ quality: 80 }).toBuffer(),
|
|
101
|
+
extension: '.webp',
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`loadConfig()` accepts either a config file or a directory. When given a directory, it searches
|
|
111
|
+
upward for the nearest `remix.json`. Run `remix assets` to list reachable files, or
|
|
112
|
+
`remix assets inspect <url-or-file>` to inspect one mapping and its access decision.
|
|
113
|
+
|
|
54
114
|
## Root Directory
|
|
55
115
|
|
|
56
116
|
Use `rootDir` to specify the root directory of the asset server, which is used to resolve relative file paths. Defaults to `process.cwd()`.
|
|
@@ -62,10 +122,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
62
122
|
let assetServer = createAssetServer({
|
|
63
123
|
rootDir: path.resolve(import.meta.dirname, '..'),
|
|
64
124
|
basePath: '/assets',
|
|
65
|
-
fileMap: {
|
|
66
|
-
'/app/*path': 'app/*path',
|
|
67
|
-
'/npm/*path': 'node_modules/*path',
|
|
68
|
-
},
|
|
69
125
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
70
126
|
allowPackages: ['remix'],
|
|
71
127
|
})
|
|
@@ -80,10 +136,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
80
136
|
|
|
81
137
|
let assetServer = createAssetServer({
|
|
82
138
|
basePath: '/assets',
|
|
83
|
-
fileMap: {
|
|
84
|
-
'/app/*path': 'app/*path',
|
|
85
|
-
'/npm/*path': 'node_modules/*path',
|
|
86
|
-
},
|
|
87
139
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
88
140
|
allowPackages: ['remix'],
|
|
89
141
|
denyFiles: ['app/**/*.server.*'],
|
|
@@ -92,27 +144,27 @@ let assetServer = createAssetServer({
|
|
|
92
144
|
|
|
93
145
|
Values for `allowFiles` and `denyFiles` are file paths or globs. Relative values are resolved from `rootDir`. Absolute file paths match exactly, and absolute directory paths also match their descendants.
|
|
94
146
|
|
|
95
|
-
Values for `allowPackages` are exact package names. Dependencies and installed optional dependencies of packages in `allowPackages` are also allowed automatically. Peer dependencies must be listed explicitly if they should be browser-reachable. Allowed package files must still be reachable through `
|
|
147
|
+
Values for `allowPackages` are exact package names. Dependencies and installed optional dependencies of packages in `allowPackages` are also allowed automatically. Peer dependencies must be listed explicitly if they should be browser-reachable. Allowed package files must still be reachable through `mounts`.
|
|
96
148
|
|
|
97
|
-
##
|
|
149
|
+
## Mounts
|
|
98
150
|
|
|
99
|
-
|
|
151
|
+
By default, the asset server mounts the `app` directory at `/app` and `node_modules` at `/npm`. Use `mounts` to replace these defaults. Keys are public paths relative to `basePath`, and values are directory paths relative to `rootDir`.
|
|
100
152
|
|
|
101
153
|
```ts
|
|
102
154
|
import { createAssetServer } from 'remix/assets'
|
|
103
155
|
|
|
104
156
|
let assetServer = createAssetServer({
|
|
105
157
|
basePath: '/assets',
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
158
|
+
mounts: {
|
|
159
|
+
source: 'app',
|
|
160
|
+
vendor: 'node_modules',
|
|
109
161
|
},
|
|
110
162
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
111
163
|
allowPackages: ['remix'],
|
|
112
164
|
})
|
|
113
165
|
```
|
|
114
166
|
|
|
115
|
-
|
|
167
|
+
Package managers that install outside `rootDir`, such as pnpm's global virtual store, are handled without configuration: the asset server reads the store location from the nearest `node_modules/.modules.yaml` and mounts it internally so those package files still resolve to public URLs. A store that a configured mount already covers, such as pnpm's default `node_modules/.pnpm`, is left alone.
|
|
116
168
|
|
|
117
169
|
### File watching
|
|
118
170
|
|
|
@@ -123,10 +175,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
123
175
|
|
|
124
176
|
let assetServer = createAssetServer({
|
|
125
177
|
basePath: '/assets',
|
|
126
|
-
fileMap: {
|
|
127
|
-
'/app/*path': 'app/*path',
|
|
128
|
-
'/npm/*path': 'node_modules/*path',
|
|
129
|
-
},
|
|
130
178
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
131
179
|
allowPackages: ['remix'],
|
|
132
180
|
})
|
|
@@ -145,10 +193,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
145
193
|
|
|
146
194
|
let assetServer = createAssetServer({
|
|
147
195
|
basePath: '/assets',
|
|
148
|
-
fileMap: {
|
|
149
|
-
'/app/*path': 'app/*path',
|
|
150
|
-
'/npm/*path': 'node_modules/*path',
|
|
151
|
-
},
|
|
152
196
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
153
197
|
allowPackages: ['remix'],
|
|
154
198
|
watch: false,
|
|
@@ -162,10 +206,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
162
206
|
|
|
163
207
|
let assetServer = createAssetServer({
|
|
164
208
|
basePath: '/assets',
|
|
165
|
-
fileMap: {
|
|
166
|
-
'/app/*path': 'app/*path',
|
|
167
|
-
'/npm/*path': 'node_modules/*path',
|
|
168
|
-
},
|
|
169
209
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
170
210
|
allowPackages: ['remix'],
|
|
171
211
|
watch: {
|
|
@@ -174,13 +214,82 @@ let assetServer = createAssetServer({
|
|
|
174
214
|
})
|
|
175
215
|
```
|
|
176
216
|
|
|
217
|
+
## Script Entries
|
|
218
|
+
|
|
219
|
+
Use `assetServer.getScriptEntry()` to get everything needed to load a script and its dependencies.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
let { href, importMap, preloads } = await assetServer.getScriptEntry('app/assets/entry.tsx')
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
This can be used when rendering a document shell:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import type { Handle, RemixNode } from 'remix/ui'
|
|
229
|
+
import { ImportMap } from 'remix/ui/server'
|
|
230
|
+
import { assetServer } from './assets.ts'
|
|
231
|
+
|
|
232
|
+
let { href, importMap, preloads } = await assetServer.getScriptEntry('app/assets/entry.tsx')
|
|
233
|
+
|
|
234
|
+
export function Document(handle: Handle<{ children: RemixNode }>) {
|
|
235
|
+
return () => (
|
|
236
|
+
<html>
|
|
237
|
+
<head>
|
|
238
|
+
{/* ... */}
|
|
239
|
+
<ImportMap value={importMap} />
|
|
240
|
+
{preloads.map((preload) => (
|
|
241
|
+
<link rel="modulepreload" href={preload} />
|
|
242
|
+
))}
|
|
243
|
+
<script type="module" src={href} />
|
|
244
|
+
</head>
|
|
245
|
+
<body>{handle.props.children}</body>
|
|
246
|
+
</html>
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
This can also be used for resolved client entries in [`remix/ui`](https://github.com/remix-run/remix/tree/main/packages/ui) when using `import.meta.url` as the client entry ID:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
import { renderToStream } from 'remix/ui/server'
|
|
255
|
+
import { assetServer } from './assets.ts'
|
|
256
|
+
|
|
257
|
+
let stream = renderToStream(<App />, {
|
|
258
|
+
async resolveClientEntry(entryId, component) {
|
|
259
|
+
let { href, importMap, preloads } = await assetServer.getScriptEntry(entryId)
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
href,
|
|
263
|
+
importMap,
|
|
264
|
+
preloads,
|
|
265
|
+
exportName: entryId.split('#')[1] || component.name,
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
// ...
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
177
272
|
## Hrefs
|
|
178
273
|
|
|
179
274
|
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.
|
|
180
275
|
|
|
181
276
|
```ts
|
|
182
|
-
let src = await assetServer.getHref('app/
|
|
183
|
-
// '/assets/app/
|
|
277
|
+
let src = await assetServer.getHref('app/media/public/logo.svg')
|
|
278
|
+
// '/assets/app/media/public/logo.svg'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Inspection
|
|
282
|
+
|
|
283
|
+
Use `getAssets()` for a sorted list of files that are currently browser-reachable through the
|
|
284
|
+
asset server. Use `getAssetDetails()` with a public URL or file path to inspect its mapping, file
|
|
285
|
+
type, access rules, and reachability status.
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
let assets = await assetServer.getAssets()
|
|
289
|
+
// [{ url: '/assets/app/actions/public/entry.ts', filePath: '/project/app/actions/public/entry.ts', ... }]
|
|
290
|
+
|
|
291
|
+
let details = await assetServer.getAssetDetails('/assets/app/actions/public/entry.ts')
|
|
292
|
+
// { status: 'reachable', type: 'script', ... }
|
|
184
293
|
```
|
|
185
294
|
|
|
186
295
|
For configured `files` assets, you can also pass a `transform` pipeline to build a request URL with custom file transforms. Basic transforms are written as strings, while dynamic transforms use `[name, param]` tuples.
|
|
@@ -192,6 +301,16 @@ let src = await assetServer.getHref('app/media/public/image.png', {
|
|
|
192
301
|
// '/assets/app/media/public/image.png?transform=resize%3A100x100&transform=webp'
|
|
193
302
|
```
|
|
194
303
|
|
|
304
|
+
## Import Maps
|
|
305
|
+
|
|
306
|
+
Scripts retain their imports as authored and rely on import maps for resolution in the browser. `assetServer.getScriptEntry()` returns the import map for a single rendered script entry. Use `assetServer.getImportMap()` directly when you need to generate a combined import map for multiple script roots or other custom graph-level behavior.
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
let importMap = await assetServer.getImportMap(['app/assets/entry.tsx', 'app/assets/search.tsx'])
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Without fingerprinting, import maps resolve authored specifiers to stable asset URLs. With fingerprinting enabled, the same import maps resolve stable asset URLs to content-fingerprinted asset URLs.
|
|
313
|
+
|
|
195
314
|
## Preloads
|
|
196
315
|
|
|
197
316
|
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.
|
|
@@ -214,29 +333,23 @@ let preloads = await assetServer.getPreloads([
|
|
|
214
333
|
|
|
215
334
|
By default, assets are served at stable URLs with ETags and `Cache-Control: no-cache`.
|
|
216
335
|
|
|
217
|
-
If you want clients to cache assets aggressively without revalidation, you can opt into
|
|
336
|
+
If you want clients to cache assets aggressively without revalidation, you can opt into content-based fingerprinting.
|
|
218
337
|
|
|
219
338
|
```ts
|
|
220
339
|
import { createAssetServer } from 'remix/assets'
|
|
221
340
|
|
|
222
341
|
let assetServer = createAssetServer({
|
|
223
342
|
basePath: '/assets',
|
|
224
|
-
fileMap: {
|
|
225
|
-
'/app/*path': 'app/*path',
|
|
226
|
-
'/npm/*path': 'node_modules/*path',
|
|
227
|
-
},
|
|
228
343
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
229
344
|
allowPackages: ['remix'],
|
|
230
345
|
watch: false,
|
|
231
|
-
fingerprint:
|
|
232
|
-
buildId: process.env.GITHUB_SHA,
|
|
233
|
-
},
|
|
346
|
+
fingerprint: true,
|
|
234
347
|
})
|
|
235
348
|
```
|
|
236
349
|
|
|
237
350
|
When fingerprinting is enabled, assets use a `.@<fingerprint>` segment before the file extension and are served with `Cache-Control: public, max-age=31536000, immutable`.
|
|
238
351
|
|
|
239
|
-
|
|
352
|
+
Fingerprints are based on emitted asset contents. This allows unchanged assets to keep the same URL across deployments, but it assumes that files on disk won't change after a URL is generated, so fingerprinting requires `watch: false`.
|
|
240
353
|
|
|
241
354
|
## Target
|
|
242
355
|
|
|
@@ -247,10 +360,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
247
360
|
|
|
248
361
|
let assetServer = createAssetServer({
|
|
249
362
|
basePath: '/assets',
|
|
250
|
-
fileMap: {
|
|
251
|
-
'/app/*path': 'app/*path',
|
|
252
|
-
'/npm/*path': 'node_modules/*path',
|
|
253
|
-
},
|
|
254
363
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
255
364
|
allowPackages: ['remix'],
|
|
256
365
|
target: {
|
|
@@ -272,10 +381,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
272
381
|
|
|
273
382
|
let assetServer = createAssetServer({
|
|
274
383
|
basePath: '/assets',
|
|
275
|
-
fileMap: {
|
|
276
|
-
'/app/*path': 'app/*path',
|
|
277
|
-
'/npm/*path': 'node_modules/*path',
|
|
278
|
-
},
|
|
279
384
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
280
385
|
allowPackages: ['remix'],
|
|
281
386
|
sourceMaps: 'external',
|
|
@@ -289,10 +394,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
289
394
|
|
|
290
395
|
let assetServer = createAssetServer({
|
|
291
396
|
basePath: '/assets',
|
|
292
|
-
fileMap: {
|
|
293
|
-
'/app/*path': 'app/*path',
|
|
294
|
-
'/npm/*path': 'node_modules/*path',
|
|
295
|
-
},
|
|
296
397
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
297
398
|
allowPackages: ['remix'],
|
|
298
399
|
sourceMaps: 'inline',
|
|
@@ -309,10 +410,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
309
410
|
|
|
310
411
|
let assetServer = createAssetServer({
|
|
311
412
|
basePath: '/assets',
|
|
312
|
-
fileMap: {
|
|
313
|
-
'/app/*path': 'app/*path',
|
|
314
|
-
'/npm/*path': 'node_modules/*path',
|
|
315
|
-
},
|
|
316
413
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
317
414
|
allowPackages: ['remix'],
|
|
318
415
|
minify: true,
|
|
@@ -330,10 +427,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
330
427
|
|
|
331
428
|
let assetServer = createAssetServer({
|
|
332
429
|
basePath: '/assets',
|
|
333
|
-
fileMap: {
|
|
334
|
-
'/app/*path': 'app/*path',
|
|
335
|
-
'/npm/*path': 'node_modules/*path',
|
|
336
|
-
},
|
|
337
430
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
338
431
|
allowPackages: ['remix'],
|
|
339
432
|
scripts: {
|
|
@@ -355,10 +448,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
355
448
|
|
|
356
449
|
let assetServer = createAssetServer({
|
|
357
450
|
basePath: '/assets',
|
|
358
|
-
fileMap: {
|
|
359
|
-
'/app/*path': 'app/*path',
|
|
360
|
-
'/npm/*path': 'node_modules/*path',
|
|
361
|
-
},
|
|
362
451
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
363
452
|
allowPackages: ['remix'],
|
|
364
453
|
scripts: {
|
|
@@ -376,7 +465,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
376
465
|
|
|
377
466
|
let assetServer = createAssetServer({
|
|
378
467
|
basePath: '/assets',
|
|
379
|
-
fileMap: { '/app/*path': 'app/*path' },
|
|
380
468
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
381
469
|
denyFiles: ['app/**/*.test.*'],
|
|
382
470
|
scripts: {
|
|
@@ -404,10 +492,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
404
492
|
|
|
405
493
|
let assetServer = createAssetServer({
|
|
406
494
|
basePath: '/assets',
|
|
407
|
-
fileMap: {
|
|
408
|
-
'/app/*path': 'app/*path',
|
|
409
|
-
'/npm/*path': 'node_modules/*path',
|
|
410
|
-
},
|
|
411
495
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
412
496
|
allowPackages: ['remix'],
|
|
413
497
|
files: {
|
|
@@ -430,10 +514,6 @@ import sharp from 'sharp'
|
|
|
430
514
|
|
|
431
515
|
let assetServer = createAssetServer({
|
|
432
516
|
basePath: '/assets',
|
|
433
|
-
fileMap: {
|
|
434
|
-
'/app/*path': 'app/*path',
|
|
435
|
-
'/npm/*path': 'node_modules/*path',
|
|
436
|
-
},
|
|
437
517
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
438
518
|
allowPackages: ['remix'],
|
|
439
519
|
files: {
|
|
@@ -464,10 +544,6 @@ import { createAssetServer, defineFileTransform } from 'remix/assets'
|
|
|
464
544
|
|
|
465
545
|
let assetServer = createAssetServer({
|
|
466
546
|
basePath: '/assets',
|
|
467
|
-
fileMap: {
|
|
468
|
-
'/app/*path': 'app/*path',
|
|
469
|
-
'/npm/*path': 'node_modules/*path',
|
|
470
|
-
},
|
|
471
547
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
472
548
|
allowPackages: ['remix'],
|
|
473
549
|
files: {
|
|
@@ -512,10 +588,6 @@ import { optimize as optimizeSvg } from 'svgo'
|
|
|
512
588
|
|
|
513
589
|
let assetServer = createAssetServer({
|
|
514
590
|
basePath: '/assets',
|
|
515
|
-
fileMap: {
|
|
516
|
-
'/app/*path': 'app/*path',
|
|
517
|
-
'/npm/*path': 'node_modules/*path',
|
|
518
|
-
},
|
|
519
591
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
520
592
|
allowPackages: ['remix'],
|
|
521
593
|
files: {
|
|
@@ -535,11 +607,9 @@ let assetServer = createAssetServer({
|
|
|
535
607
|
|
|
536
608
|
#### File transform caching
|
|
537
609
|
|
|
538
|
-
Use `files.cache` to store transformed file outputs via a [`file-storage`](https://github.com/remix-run/remix/tree/main/packages/file-storage) backend.
|
|
610
|
+
Use `files.cache` to store transformed file outputs via a [`file-storage`](https://github.com/remix-run/remix/tree/main/packages/file-storage) backend. Without `files.cache`, transformed file outputs are recomputed per request.
|
|
539
611
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
If `fingerprint.buildId` is set, the file cache can be reused across server restarts for the same build.
|
|
612
|
+
`files.cacheKey` scopes transformed file cache entries. Use a stable identifier, such as a commit SHA, when you want unchanged transformed files to be reused across server restarts for the same build.
|
|
543
613
|
|
|
544
614
|
```ts
|
|
545
615
|
import * as path from 'node:path'
|
|
@@ -548,14 +618,11 @@ import { createFsFileStorage } from 'remix/file-storage/fs'
|
|
|
548
618
|
|
|
549
619
|
let assetServer = createAssetServer({
|
|
550
620
|
basePath: '/assets',
|
|
551
|
-
fileMap: {
|
|
552
|
-
'/app/*path': 'app/*path',
|
|
553
|
-
'/npm/*path': 'node_modules/*path',
|
|
554
|
-
},
|
|
555
621
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
556
622
|
allowPackages: ['remix'],
|
|
557
623
|
files: {
|
|
558
624
|
cache: createFsFileStorage(path.resolve('.tmp/assets-cache')),
|
|
625
|
+
cacheKey: process.env.GIT_COMMIT_SHA,
|
|
559
626
|
extensions: ['.svg', '.png', '.jpg', '.jpeg', '.woff2'],
|
|
560
627
|
transforms: {
|
|
561
628
|
/*...*/
|
|
@@ -573,10 +640,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
573
640
|
|
|
574
641
|
let assetServer = createAssetServer({
|
|
575
642
|
basePath: '/assets',
|
|
576
|
-
fileMap: {
|
|
577
|
-
'/app/*path': 'app/*path',
|
|
578
|
-
'/npm/*path': 'node_modules/*path',
|
|
579
|
-
},
|
|
580
643
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
581
644
|
allowPackages: ['remix'],
|
|
582
645
|
files: {
|
|
@@ -624,10 +687,6 @@ import { createAssetServer } from 'remix/assets'
|
|
|
624
687
|
|
|
625
688
|
let assetServer = createAssetServer({
|
|
626
689
|
basePath: '/assets',
|
|
627
|
-
fileMap: {
|
|
628
|
-
'/app/*path': 'app/*path',
|
|
629
|
-
'/npm/*path': 'node_modules/*path',
|
|
630
|
-
},
|
|
631
690
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
632
691
|
allowPackages: ['remix'],
|
|
633
692
|
onError(error) {
|
|
@@ -651,9 +710,8 @@ import { createAssetServer } from 'remix/assets'
|
|
|
651
710
|
let isDevelopment = process.env.NODE_ENV === 'development'
|
|
652
711
|
let assetServer = createAssetServer({
|
|
653
712
|
basePath: '/assets',
|
|
654
|
-
fileMap: { '/app/*path': 'app/*path' },
|
|
655
713
|
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
656
|
-
|
|
714
|
+
allowPackages: ['remix'],
|
|
657
715
|
hmr: isDevelopment
|
|
658
716
|
? async () => (await import('remix/node-hmr/runtime')).createBrowserHmrChannel()
|
|
659
717
|
: undefined,
|
|
@@ -661,6 +719,30 @@ let assetServer = createAssetServer({
|
|
|
661
719
|
})
|
|
662
720
|
```
|
|
663
721
|
|
|
722
|
+
Use `moduleImporter` to customize how HMR dynamically imports updated browser modules. It is resolved relative to the asset server's root directory and must point to a browser module exporting:
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
export function importModule(specifier: string, parentUrl: string): Promise<Record<string, unknown>>
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
HMR appends mappings for updated modules to the document in additional `<script type="importmap">` elements. Use `remix/multiple-import-maps-polyfill` when these updates must work in browsers without native support for multiple import maps:
|
|
729
|
+
|
|
730
|
+
```ts
|
|
731
|
+
import { createAssetServer } from 'remix/assets'
|
|
732
|
+
import { createBrowserHmrChannel } from 'remix/node-hmr/runtime'
|
|
733
|
+
|
|
734
|
+
let assetServer = createAssetServer({
|
|
735
|
+
basePath: '/assets',
|
|
736
|
+
allowFiles: ['app/routes.ts', 'app/**/public/**'],
|
|
737
|
+
allowPackages: ['remix'],
|
|
738
|
+
hmr: {
|
|
739
|
+
channel: createBrowserHmrChannel,
|
|
740
|
+
moduleImporter: 'remix/multiple-import-maps-polyfill',
|
|
741
|
+
},
|
|
742
|
+
watch: true,
|
|
743
|
+
})
|
|
744
|
+
```
|
|
745
|
+
|
|
664
746
|
### `import.meta.hot`
|
|
665
747
|
|
|
666
748
|
The `import.meta.hot` API provided by `assets` is a small runtime contract for modules that can handle updates without reloading the page. It is primarily intended for browser modules compiled by `assets`, but it can also be used directly.
|
|
@@ -798,7 +880,6 @@ if (import.meta.hot) {
|
|
|
798
880
|
- [`fetch-router`](https://github.com/remix-run/remix/tree/main/packages/fetch-router) - A Fetch-based router that pairs naturally with `assets`
|
|
799
881
|
- [`node-hmr`](https://github.com/remix-run/remix/tree/main/packages/node-hmr) - Provides the server-side `import.meta.hot` runtime and browser HMR channel used by `hmr`
|
|
800
882
|
- [`ui-hmr`](https://github.com/remix-run/remix/tree/main/packages/ui-hmr) - Provides a Remix UI component HMR loader for `scripts.loaders`
|
|
801
|
-
- [`route-pattern`](https://github.com/remix-run/remix/tree/main/packages/route-pattern) - Route-pattern syntax for URL and route file matching
|
|
802
883
|
|
|
803
884
|
## License
|
|
804
885
|
|
package/dist/assets.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { createAssetServer } from './lib/asset-server.ts';
|
|
2
2
|
export { defineFileTransform } from './lib/files/config.ts';
|
|
3
|
-
export type {
|
|
3
|
+
export type { AssetAccessDetails, AssetAccessRule } from './lib/access.ts';
|
|
4
|
+
export type { AssetServer, AssetServerOptions, BrowserHmrChannel, ScriptEntry, } from './lib/asset-server.ts';
|
|
5
|
+
export type { AssetDetails, AssetKind, AssetStatus } from './lib/inspection.ts';
|
|
6
|
+
export type { ScriptImportMap } from './lib/scripts/compiler.ts';
|
|
4
7
|
export type { ModuleLoader } from './lib/loaders.ts';
|
|
5
8
|
//# sourceMappingURL=assets.d.ts.map
|
package/dist/assets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC1E,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC/E,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA"}
|
package/dist/lib/access.d.ts
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
/** Access-policy result for an inspected asset file. */
|
|
2
|
+
export interface AssetAccessDetails {
|
|
3
|
+
/** Whether the asset server may serve the file. */
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
/** The first configured rule that allowed the file, when one matched. */
|
|
6
|
+
allowedBy?: AssetAccessRule;
|
|
7
|
+
/** The first matching `denyFiles` pattern, when access was denied. */
|
|
8
|
+
deniedBy?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Rule that allows an inspected asset file to be served. */
|
|
11
|
+
export type AssetAccessRule =
|
|
12
|
+
/** A matching `allowFiles` entry. */
|
|
13
|
+
{
|
|
14
|
+
kind: 'file';
|
|
15
|
+
value: string;
|
|
16
|
+
}
|
|
17
|
+
/** A runtime file provided internally by the asset server. */
|
|
18
|
+
| {
|
|
19
|
+
kind: 'injected';
|
|
20
|
+
value: string;
|
|
21
|
+
}
|
|
22
|
+
/** A matching `allowPackages` entry. */
|
|
23
|
+
| {
|
|
24
|
+
kind: 'package';
|
|
25
|
+
value: string;
|
|
26
|
+
};
|
|
27
|
+
export type AccessPolicy = {
|
|
28
|
+
getAllowedPackageRoots(): readonly string[];
|
|
2
29
|
getPackageWatchDirectories(): readonly string[];
|
|
3
30
|
handleFileEvent(filePath: string): void;
|
|
31
|
+
inspect(filePath: string): AssetAccessDetails;
|
|
4
32
|
isAllowed(filePath: string): boolean;
|
|
5
33
|
};
|
|
6
34
|
export declare function createAccessPolicy(options: {
|
|
@@ -10,5 +38,4 @@ export declare function createAccessPolicy(options: {
|
|
|
10
38
|
packageSearchRoots?: readonly string[];
|
|
11
39
|
rootDir: string;
|
|
12
40
|
}): AccessPolicy;
|
|
13
|
-
export {};
|
|
14
41
|
//# sourceMappingURL=access.d.ts.map
|
package/dist/lib/access.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/lib/access.ts"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/lib/access.ts"],"names":[],"mappings":"AAMA,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAA;IAChB,yEAAyE;IACzE,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,6DAA6D;AAC7D,MAAM,MAAM,eAAe;AACzB,qCAAqC;AACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACjC,8DAA8D;GAC5D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACrC,wCAAwC;GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,MAAM,MAAM,YAAY,GAAG;IACzB,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAC3C,0BAA0B,IAAI,SAAS,MAAM,EAAE,CAAA;IAC/C,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAA;IAC7C,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;CACrC,CAAA;AAcD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,YAAY,CAoFf"}
|