@remix-run/assets 0.6.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 +101 -13
- package/dist/assets.d.ts +2 -1
- package/dist/assets.d.ts.map +1 -1
- package/dist/lib/asset-server.d.ts +41 -19
- package/dist/lib/asset-server.d.ts.map +1 -1
- package/dist/lib/asset-server.js +98 -41
- 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 +26 -29
- 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/routes.d.ts +1 -0
- package/dist/lib/routes.d.ts.map +1 -1
- package/dist/lib/routes.js +1 -1
- 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 +186 -36
- 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 +110 -3
- 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 +2 -16
- 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 +0 -1
- 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 +0 -7
- 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 -5
- package/src/assets.ts +7 -1
- package/src/lib/asset-server.ts +175 -73
- package/src/lib/compilation-error.ts +1 -0
- package/src/lib/files/compiler.ts +30 -40
- 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/routes.ts +1 -1
- package/src/lib/scripts/compiler.ts +238 -52
- package/src/lib/scripts/emit.ts +34 -19
- package/src/lib/scripts/resolve.ts +166 -4
- package/src/lib/scripts/specifiers.ts +11 -0
- package/src/lib/scripts/transform.ts +4 -23
- package/src/lib/styles/compiler.ts +137 -39
- package/src/lib/styles/emit.ts +18 -13
- package/src/lib/styles/resolve.ts +0 -2
- package/src/lib/styles/transform.ts +0 -10
- package/src/lib/virtual-store.ts +124 -0
package/src/lib/styles/emit.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
createAssetServerCompilationError,
|
|
5
5
|
isAssetServerCompilationError,
|
|
6
6
|
} from '../compilation-error.ts'
|
|
7
|
-
import { hashContent } from '../fingerprint.ts'
|
|
7
|
+
import { formatFingerprintedPathname, hashContent } from '../fingerprint.ts'
|
|
8
8
|
import { composeSourceMaps } from '../source-maps.ts'
|
|
9
9
|
import type { AssetServerCompilationError } from '../compilation-error.ts'
|
|
10
10
|
import type { ResolvedStyle } from './resolve.ts'
|
|
@@ -12,12 +12,12 @@ import type { ResolvedStyle } from './resolve.ts'
|
|
|
12
12
|
export type EmittedAsset = {
|
|
13
13
|
content: string
|
|
14
14
|
etag: string
|
|
15
|
+
fingerprint: string
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export type EmittedStyle = {
|
|
18
19
|
code: EmittedAsset
|
|
19
20
|
fingerprint: string | null
|
|
20
|
-
importUrls: string[]
|
|
21
21
|
sourceMap: EmittedAsset | null
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -34,6 +34,7 @@ type EmitResult =
|
|
|
34
34
|
export async function emitResolvedStyle(
|
|
35
35
|
resolvedStyle: ResolvedStyle,
|
|
36
36
|
options: {
|
|
37
|
+
fingerprintAssets: boolean
|
|
37
38
|
getServedFileUrl?(
|
|
38
39
|
identityPath: string,
|
|
39
40
|
options: {
|
|
@@ -45,30 +46,32 @@ export async function emitResolvedStyle(
|
|
|
45
46
|
},
|
|
46
47
|
): Promise<EmitResult> {
|
|
47
48
|
try {
|
|
48
|
-
let importUrls = await Promise.all(
|
|
49
|
-
resolvedStyle.deps.map((depPath) => options.getServedUrl(depPath)),
|
|
50
|
-
)
|
|
51
49
|
let rewriteResult = await rewriteDependencies(resolvedStyle, options)
|
|
52
50
|
let finalCode = rewriteResult.code
|
|
51
|
+
let sourceMap = rewriteResult.sourceMap
|
|
52
|
+
? await createEmittedAsset(rewriteResult.sourceMap)
|
|
53
|
+
: null
|
|
53
54
|
|
|
54
55
|
if (rewriteResult.sourceMap) {
|
|
55
56
|
if (options.sourceMaps === 'inline') {
|
|
56
57
|
let encoded = Buffer.from(rewriteResult.sourceMap).toString('base64')
|
|
57
58
|
finalCode += `\n/*# sourceMappingURL=data:application/json;base64,${encoded} */`
|
|
58
59
|
} else if (options.sourceMaps === 'external') {
|
|
59
|
-
finalCode += `\n/*# sourceMappingURL=${
|
|
60
|
+
finalCode += `\n/*# sourceMappingURL=${formatFingerprintedPathname(
|
|
61
|
+
resolvedStyle.stableUrlPathname,
|
|
62
|
+
options.fingerprintAssets && sourceMap ? sourceMap.fingerprint : null,
|
|
63
|
+
)}.map */`
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
let code = await createEmittedAsset(finalCode)
|
|
68
|
+
|
|
63
69
|
return {
|
|
64
70
|
ok: true,
|
|
65
71
|
value: {
|
|
66
|
-
code
|
|
67
|
-
fingerprint:
|
|
68
|
-
|
|
69
|
-
sourceMap: rewriteResult.sourceMap
|
|
70
|
-
? await createEmittedAsset(rewriteResult.sourceMap)
|
|
71
|
-
: null,
|
|
72
|
+
code,
|
|
73
|
+
fingerprint: options.fingerprintAssets ? code.fingerprint : null,
|
|
74
|
+
sourceMap,
|
|
72
75
|
},
|
|
73
76
|
}
|
|
74
77
|
} catch (error) {
|
|
@@ -192,9 +195,11 @@ async function getServedFileUrl(
|
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
async function createEmittedAsset(content: string): Promise<EmittedAsset> {
|
|
198
|
+
let fingerprint = await hashContent(content)
|
|
195
199
|
return {
|
|
196
200
|
content,
|
|
197
|
-
etag: `W/"${
|
|
201
|
+
etag: `W/"${fingerprint}"`,
|
|
202
|
+
fingerprint,
|
|
198
203
|
}
|
|
199
204
|
}
|
|
200
205
|
|
|
@@ -38,7 +38,6 @@ type ResolvedDependency =
|
|
|
38
38
|
export type ResolvedStyle = {
|
|
39
39
|
dependencies: ResolvedDependency[]
|
|
40
40
|
deps: string[]
|
|
41
|
-
fingerprint: string | null
|
|
42
41
|
identityPath: string
|
|
43
42
|
rawCode: string
|
|
44
43
|
resolvedPath: string
|
|
@@ -131,7 +130,6 @@ export async function resolveStyle(
|
|
|
131
130
|
value: {
|
|
132
131
|
dependencies,
|
|
133
132
|
deps: [...deps],
|
|
134
|
-
fingerprint: transformed.fingerprint,
|
|
135
133
|
identityPath: record.identityPath,
|
|
136
134
|
rawCode: transformed.rawCode,
|
|
137
135
|
resolvedPath: transformed.resolvedPath,
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
createAssetServerCompilationError,
|
|
6
6
|
isAssetServerCompilationError,
|
|
7
7
|
} from '../compilation-error.ts'
|
|
8
|
-
import { generateFingerprint } from '../fingerprint.ts'
|
|
9
8
|
import type { ModuleTracking } from '../module-store.ts'
|
|
10
9
|
import { rewriteSourceMapSources, stringifySourceMap } from '../source-maps.ts'
|
|
11
10
|
import type { AssetServerCompilationError } from '../compilation-error.ts'
|
|
@@ -25,7 +24,6 @@ type TransformedStyleDependency =
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export type TransformedStyle = {
|
|
28
|
-
fingerprint: string | null
|
|
29
27
|
identityPath: string
|
|
30
28
|
rawCode: string
|
|
31
29
|
resolvedPath: string
|
|
@@ -49,7 +47,6 @@ type TransformResult = {
|
|
|
49
47
|
)
|
|
50
48
|
|
|
51
49
|
export type TransformArgs = {
|
|
52
|
-
buildId: string | null
|
|
53
50
|
isWatchIgnored(filePath: string): boolean
|
|
54
51
|
minify: boolean
|
|
55
52
|
routes: CompiledRoutes
|
|
@@ -149,13 +146,6 @@ export async function transformStyle(
|
|
|
149
146
|
trackedFiles,
|
|
150
147
|
},
|
|
151
148
|
value: {
|
|
152
|
-
fingerprint:
|
|
153
|
-
args.buildId === null
|
|
154
|
-
? null
|
|
155
|
-
: await generateFingerprint({
|
|
156
|
-
buildId: args.buildId,
|
|
157
|
-
content: sourceText,
|
|
158
|
-
}),
|
|
159
149
|
identityPath: record.identityPath,
|
|
160
150
|
rawCode: Buffer.from(transformResult.code).toString('utf8'),
|
|
161
151
|
resolvedPath,
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getFilePathBaseName,
|
|
6
|
+
getFilePathDirectory,
|
|
7
|
+
normalizeFilePath,
|
|
8
|
+
resolveFilePath,
|
|
9
|
+
} from './paths.ts'
|
|
10
|
+
import { resolveMountFileRoot } from './routes.ts'
|
|
11
|
+
|
|
12
|
+
const modulesStateFileName = '.modules.yaml'
|
|
13
|
+
const virtualStoreBasePath = '/__@remix/virtual-store'
|
|
14
|
+
const virtualStoreDirLineRE = /^virtualStoreDir:[ \t]*(.+)$/m
|
|
15
|
+
|
|
16
|
+
// pnpm's global virtual store links packages from a machine-wide directory, so package realpaths
|
|
17
|
+
// land outside `rootDir` and would otherwise have no public URL. The store location comes from
|
|
18
|
+
// `node_modules/.modules.yaml`, which pnpm rewrites on every install.
|
|
19
|
+
export function getVirtualStoreMountConfigs(options: {
|
|
20
|
+
mounts: Readonly<Record<string, string>>
|
|
21
|
+
rootDir: string
|
|
22
|
+
}): {
|
|
23
|
+
mounts: Record<string, string>
|
|
24
|
+
rootDir: string
|
|
25
|
+
}[] {
|
|
26
|
+
let virtualStoreDir = findVirtualStoreDir(options.rootDir)
|
|
27
|
+
if (virtualStoreDir === null) return []
|
|
28
|
+
// A store inside a mount, such as pnpm's default `node_modules/.pnpm`, already has URLs.
|
|
29
|
+
if (isWithinMounts(virtualStoreDir, options)) return []
|
|
30
|
+
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
mounts: {
|
|
34
|
+
[virtualStoreBasePath]: getFilePathBaseName(virtualStoreDir),
|
|
35
|
+
},
|
|
36
|
+
rootDir: getFilePathDirectory(virtualStoreDir),
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function findVirtualStoreDir(rootDir: string): string | null {
|
|
42
|
+
let directory = normalizeFilePath(rootDir)
|
|
43
|
+
|
|
44
|
+
// Workspace members share the workspace root's file, so walk up to the nearest one.
|
|
45
|
+
while (true) {
|
|
46
|
+
let modulesDir = `${directory}/node_modules`
|
|
47
|
+
let modulesState = readModulesState(`${modulesDir}/${modulesStateFileName}`)
|
|
48
|
+
if (modulesState !== null) {
|
|
49
|
+
let virtualStoreDir = readVirtualStoreDir(modulesState)
|
|
50
|
+
if (virtualStoreDir === null) return null
|
|
51
|
+
return realpathDirectory(resolveFilePath(modulesDir, virtualStoreDir))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let parentDirectory = normalizeFilePath(path.dirname(directory))
|
|
55
|
+
if (parentDirectory === directory) return null
|
|
56
|
+
directory = parentDirectory
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readVirtualStoreDir(modulesState: string): string | null {
|
|
61
|
+
// pnpm 10.34 and later write JSON, earlier versions write YAML, and package managers that
|
|
62
|
+
// mirror the global virtual store write either one. Reading the one scalar this needs keeps
|
|
63
|
+
// both formats working without a YAML parser.
|
|
64
|
+
try {
|
|
65
|
+
let parsedState = JSON.parse(modulesState) as unknown
|
|
66
|
+
if (parsedState === null || typeof parsedState !== 'object') return null
|
|
67
|
+
|
|
68
|
+
let virtualStoreDir = (parsedState as Record<string, unknown>).virtualStoreDir
|
|
69
|
+
return typeof virtualStoreDir === 'string' ? virtualStoreDir : null
|
|
70
|
+
} catch {
|
|
71
|
+
let match = virtualStoreDirLineRE.exec(modulesState)
|
|
72
|
+
return match === null ? null : unquoteScalar(match[1].trim())
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function unquoteScalar(value: string): string {
|
|
77
|
+
let quote = value[0]
|
|
78
|
+
if (value.length > 1 && (quote === "'" || quote === '"') && value.endsWith(quote)) {
|
|
79
|
+
return value.slice(1, -1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return value
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isWithinMounts(
|
|
86
|
+
directory: string,
|
|
87
|
+
options: {
|
|
88
|
+
mounts: Readonly<Record<string, string>>
|
|
89
|
+
rootDir: string
|
|
90
|
+
},
|
|
91
|
+
): boolean {
|
|
92
|
+
return Object.values(options.mounts).some((fileRoot) => {
|
|
93
|
+
let mountRoot = resolveMountFileRoot(options.rootDir, fileRoot)
|
|
94
|
+
return directory === mountRoot || directory.startsWith(`${mountRoot}/`)
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readModulesState(filePath: string): string | null {
|
|
99
|
+
try {
|
|
100
|
+
return fs.readFileSync(filePath, 'utf-8')
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (isPathNotFoundError(error)) return null
|
|
103
|
+
throw error
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function realpathDirectory(filePath: string): string | null {
|
|
108
|
+
try {
|
|
109
|
+
let realPath = fs.realpathSync(filePath)
|
|
110
|
+
return fs.statSync(realPath).isDirectory() ? normalizeFilePath(realPath) : null
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (isPathNotFoundError(error)) return null
|
|
113
|
+
throw error
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isPathNotFoundError(error: unknown): boolean {
|
|
118
|
+
return (
|
|
119
|
+
error instanceof Error &&
|
|
120
|
+
'code' in error &&
|
|
121
|
+
((error as NodeJS.ErrnoException).code === 'ENOENT' ||
|
|
122
|
+
(error as NodeJS.ErrnoException).code === 'ENOTDIR')
|
|
123
|
+
)
|
|
124
|
+
}
|