@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
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
|
|
4
|
+
import { normalizeFilePath } from "../paths.js";
|
|
5
|
+
export async function resolveStyle(record, transformed, args) {
|
|
6
|
+
let trackedFiles = new Set(transformed.trackedFiles);
|
|
7
|
+
let dependencies = [];
|
|
8
|
+
let deps = new Set();
|
|
9
|
+
for (let unresolved of transformed.unresolvedDependencies) {
|
|
10
|
+
let trackedFile = unresolved.type === 'import'
|
|
11
|
+
? getTrackedImportFilePath(unresolved.url, transformed.resolvedPath)
|
|
12
|
+
: null;
|
|
13
|
+
if (trackedFile && !args.isWatchIgnored(trackedFile)) {
|
|
14
|
+
trackedFiles.add(trackedFile);
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
let resolved = unresolved.type === 'import'
|
|
18
|
+
? resolveImportDependency(unresolved.url, transformed.resolvedPath, unresolved.placeholder, args)
|
|
19
|
+
: resolveUrlDependency(unresolved.url, unresolved.placeholder);
|
|
20
|
+
dependencies.push(resolved);
|
|
21
|
+
if (resolved.kind === 'local') {
|
|
22
|
+
if (!args.isWatchIgnored(resolved.depPath)) {
|
|
23
|
+
trackedFiles.add(resolved.depPath);
|
|
24
|
+
}
|
|
25
|
+
deps.add(resolved.depPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return failResolve(error, trackedFiles, transformed.resolvedPath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
tracking: {
|
|
35
|
+
trackedFiles: [...trackedFiles],
|
|
36
|
+
},
|
|
37
|
+
value: {
|
|
38
|
+
dependencies,
|
|
39
|
+
deps: [...deps],
|
|
40
|
+
fingerprint: transformed.fingerprint,
|
|
41
|
+
identityPath: record.identityPath,
|
|
42
|
+
rawCode: transformed.rawCode,
|
|
43
|
+
resolvedPath: transformed.resolvedPath,
|
|
44
|
+
sourceMap: transformed.sourceMap,
|
|
45
|
+
stableUrlPathname: transformed.stableUrlPathname,
|
|
46
|
+
trackedFiles: [...trackedFiles],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function resolveServedStyleOrThrow(filePath, args) {
|
|
51
|
+
let identityPath = resolveExistingFilePath(filePath);
|
|
52
|
+
if (!identityPath) {
|
|
53
|
+
throw createAssetServerCompilationError(`File not found: ${filePath}`, {
|
|
54
|
+
code: 'FILE_NOT_FOUND',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (!isStyleFilePath(identityPath)) {
|
|
58
|
+
throw createAssetServerCompilationError(`File not found: ${identityPath}`, {
|
|
59
|
+
code: 'FILE_NOT_FOUND',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (!args.isAllowed(identityPath)) {
|
|
63
|
+
throw createAssetServerCompilationError(`File is not allowed: ${identityPath}`, {
|
|
64
|
+
code: 'FILE_NOT_ALLOWED',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
let stableUrlPathname = args.routes.toUrlPathname(identityPath);
|
|
68
|
+
if (!stableUrlPathname) {
|
|
69
|
+
throw createAssetServerCompilationError(`File ${identityPath} is outside all configured fileMap entries.`, {
|
|
70
|
+
code: 'FILE_OUTSIDE_FILE_MAP',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return { identityPath, stableUrlPathname };
|
|
74
|
+
}
|
|
75
|
+
function resolveImportDependency(url, importerPath, placeholder, args) {
|
|
76
|
+
if (isExternalUrl(url)) {
|
|
77
|
+
return {
|
|
78
|
+
kind: 'external',
|
|
79
|
+
placeholder,
|
|
80
|
+
replacement: url,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
let { pathname, suffix } = splitUrlSuffix(url);
|
|
84
|
+
if (pathname.length === 0 || pathname === '#') {
|
|
85
|
+
return {
|
|
86
|
+
kind: 'external',
|
|
87
|
+
placeholder,
|
|
88
|
+
replacement: url,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (pathname.startsWith('/')) {
|
|
92
|
+
return {
|
|
93
|
+
kind: 'external',
|
|
94
|
+
placeholder,
|
|
95
|
+
replacement: url,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
let resolvedFilePath = normalizeFilePath(path.resolve(path.dirname(importerPath), pathname));
|
|
99
|
+
let identityPath = resolveExistingFilePath(resolvedFilePath);
|
|
100
|
+
if (!identityPath || !isStyleFilePath(identityPath)) {
|
|
101
|
+
throw createAssetServerCompilationError(`Failed to resolve import "${url}" in ${importerPath}.`, {
|
|
102
|
+
code: 'IMPORT_RESOLUTION_FAILED',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (!args.isAllowed(identityPath)) {
|
|
106
|
+
throw createAssetServerCompilationError(`Import "${url}" in ${importerPath}, resolved to "${identityPath}", is not allowed by the asset server allow/deny configuration. ` +
|
|
107
|
+
`Add a matching allow rule for this file path, remove a conflicting deny rule for this file path, or mark this import as external.`, {
|
|
108
|
+
code: 'IMPORT_NOT_ALLOWED',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (!args.routes.toUrlPathname(identityPath)) {
|
|
112
|
+
throw createAssetServerCompilationError(`Import "${url}" in ${importerPath}, resolved to "${identityPath}", is outside all configured fileMap entries. ` +
|
|
113
|
+
`Add a matching fileMap entry for this file path, or mark this import as external.`, {
|
|
114
|
+
code: 'IMPORT_OUTSIDE_FILE_MAP',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
depPath: identityPath,
|
|
119
|
+
kind: 'local',
|
|
120
|
+
placeholder,
|
|
121
|
+
suffix,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function resolveUrlDependency(url, placeholder) {
|
|
125
|
+
return {
|
|
126
|
+
kind: 'external',
|
|
127
|
+
placeholder,
|
|
128
|
+
replacement: url,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function resolveExistingFilePath(filePath) {
|
|
132
|
+
try {
|
|
133
|
+
return normalizeFilePath(fs.realpathSync(filePath));
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (isNoEntityError(error))
|
|
137
|
+
return null;
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function splitUrlSuffix(url) {
|
|
142
|
+
let queryIndex = url.indexOf('?');
|
|
143
|
+
let hashIndex = url.indexOf('#');
|
|
144
|
+
let endIndex = [queryIndex, hashIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
|
|
145
|
+
if (endIndex == null) {
|
|
146
|
+
return {
|
|
147
|
+
pathname: url,
|
|
148
|
+
suffix: '',
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
pathname: url.slice(0, endIndex),
|
|
153
|
+
suffix: url.slice(endIndex),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function getTrackedImportFilePath(specifier, importerPath) {
|
|
157
|
+
let { pathname } = splitUrlSuffix(specifier);
|
|
158
|
+
if (pathname.startsWith('./') || pathname.startsWith('../')) {
|
|
159
|
+
return normalizeFilePath(path.resolve(path.dirname(importerPath), pathname));
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
function isStyleFilePath(filePath) {
|
|
164
|
+
return path.extname(filePath).toLowerCase() === '.css';
|
|
165
|
+
}
|
|
166
|
+
function isExternalUrl(url) {
|
|
167
|
+
return url.startsWith('#') || url.startsWith('//') || /^[A-Za-z][A-Za-z\d+.-]*:/.test(url);
|
|
168
|
+
}
|
|
169
|
+
function isNoEntityError(error) {
|
|
170
|
+
return (error instanceof Error && 'code' in error && error.code === 'ENOENT');
|
|
171
|
+
}
|
|
172
|
+
function toResolveError(error, importerPath) {
|
|
173
|
+
if (isAssetServerCompilationError(error))
|
|
174
|
+
return error;
|
|
175
|
+
return createAssetServerCompilationError(`Failed to resolve imports in ${importerPath}. ${error instanceof Error ? error.message : String(error)}`, {
|
|
176
|
+
cause: error,
|
|
177
|
+
code: 'IMPORT_RESOLUTION_FAILED',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function failResolve(error, trackedFiles, importerPath) {
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
error: toResolveError(error, importerPath),
|
|
184
|
+
tracking: {
|
|
185
|
+
trackedFiles: [...trackedFiles],
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ModuleTracking } from '../module-store.ts';
|
|
2
|
+
import type { AssetServerCompilationError } from '../compilation-error.ts';
|
|
3
|
+
import type { CompiledRoutes } from '../routes.ts';
|
|
4
|
+
import type { ResolvedStyleTarget } from '../target.ts';
|
|
5
|
+
type TransformedStyleDependency = {
|
|
6
|
+
placeholder: string;
|
|
7
|
+
type: 'import';
|
|
8
|
+
url: string;
|
|
9
|
+
} | {
|
|
10
|
+
placeholder: string;
|
|
11
|
+
type: 'url';
|
|
12
|
+
url: string;
|
|
13
|
+
};
|
|
14
|
+
export type TransformedStyle = {
|
|
15
|
+
fingerprint: string | null;
|
|
16
|
+
identityPath: string;
|
|
17
|
+
rawCode: string;
|
|
18
|
+
resolvedPath: string;
|
|
19
|
+
sourceMap: string | null;
|
|
20
|
+
stableUrlPathname: string;
|
|
21
|
+
trackedFiles: string[];
|
|
22
|
+
unresolvedDependencies: TransformedStyleDependency[];
|
|
23
|
+
};
|
|
24
|
+
type TransformResult = {
|
|
25
|
+
tracking: ModuleTracking;
|
|
26
|
+
} & ({
|
|
27
|
+
ok: true;
|
|
28
|
+
value: TransformedStyle;
|
|
29
|
+
} | {
|
|
30
|
+
error: AssetServerCompilationError;
|
|
31
|
+
ok: false;
|
|
32
|
+
});
|
|
33
|
+
export type TransformArgs = {
|
|
34
|
+
buildId: string | null;
|
|
35
|
+
isWatchIgnored(filePath: string): boolean;
|
|
36
|
+
minify: boolean;
|
|
37
|
+
routes: CompiledRoutes;
|
|
38
|
+
sourceMaps: 'external' | 'inline' | null;
|
|
39
|
+
sourceMapSourcePaths: 'absolute' | 'url';
|
|
40
|
+
targets: ResolvedStyleTarget | null;
|
|
41
|
+
};
|
|
42
|
+
type TransformRecord = {
|
|
43
|
+
identityPath: string;
|
|
44
|
+
};
|
|
45
|
+
export declare function transformStyle(record: TransformRecord, args: TransformArgs): Promise<TransformResult>;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/lib/styles/transform.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEvD,KAAK,0BAA0B,GAC3B;IACE,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ,GACD;IACE,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,KAAK,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAEL,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,sBAAsB,EAAE,0BAA0B,EAAE,CAAA;CACrD,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,gBAAgB,CAAA;CACxB,GACD;IACE,KAAK,EAAE,2BAA2B,CAAA;IAClC,EAAE,EAAE,KAAK,CAAA;CACV,CACJ,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;IACtB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAA;IACxC,oBAAoB,EAAE,UAAU,GAAG,KAAK,CAAA;IACxC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,eAAe,CAAC,CA6G1B"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { transform } from 'lightningcss';
|
|
3
|
+
import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
|
|
4
|
+
import { generateFingerprint } from "../fingerprint.js";
|
|
5
|
+
import { rewriteSourceMapSources, stringifySourceMap } from "../source-maps.js";
|
|
6
|
+
export async function transformStyle(record, args) {
|
|
7
|
+
let resolvedPath = record.identityPath;
|
|
8
|
+
let trackedFiles = args.isWatchIgnored(resolvedPath) ? [] : [resolvedPath];
|
|
9
|
+
let rawBytes;
|
|
10
|
+
try {
|
|
11
|
+
rawBytes = new Uint8Array(await fs.readFile(resolvedPath));
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (isNoEntityError(error)) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
error: createAssetServerCompilationError(`File not found: ${resolvedPath}`, {
|
|
18
|
+
cause: error,
|
|
19
|
+
code: 'FILE_NOT_FOUND',
|
|
20
|
+
}),
|
|
21
|
+
tracking: {
|
|
22
|
+
trackedFiles,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
error: toTransformFailedError(error, resolvedPath),
|
|
29
|
+
tracking: {
|
|
30
|
+
trackedFiles,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
let stableUrlPathname = args.routes.toUrlPathname(record.identityPath);
|
|
36
|
+
if (!stableUrlPathname) {
|
|
37
|
+
throw createAssetServerCompilationError(`File ${record.identityPath} is outside all configured fileMap entries.`, {
|
|
38
|
+
code: 'FILE_OUTSIDE_FILE_MAP',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
let transformResult = runLightningTransform(resolvedPath, rawBytes, {
|
|
42
|
+
minify: args.minify,
|
|
43
|
+
sourceMap: args.sourceMaps != null,
|
|
44
|
+
targets: args.targets,
|
|
45
|
+
});
|
|
46
|
+
let sourceText = Buffer.from(rawBytes).toString('utf8');
|
|
47
|
+
let sourceMap = stringifySourceMap(transformResult.map);
|
|
48
|
+
sourceMap = sourceMap
|
|
49
|
+
? rewriteSourceMapSources(sourceMap, resolvedPath, stableUrlPathname, args.sourceMapSourcePaths, sourceText)
|
|
50
|
+
: null;
|
|
51
|
+
let unresolvedDependencies = [];
|
|
52
|
+
for (let dependency of transformResult.dependencies ?? []) {
|
|
53
|
+
if (dependency.type === 'import') {
|
|
54
|
+
unresolvedDependencies.push({
|
|
55
|
+
placeholder: dependency.placeholder,
|
|
56
|
+
type: 'import',
|
|
57
|
+
url: dependency.url,
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (dependency.type === 'url') {
|
|
62
|
+
unresolvedDependencies.push({
|
|
63
|
+
placeholder: dependency.placeholder,
|
|
64
|
+
type: 'url',
|
|
65
|
+
url: dependency.url,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
ok: true,
|
|
71
|
+
tracking: {
|
|
72
|
+
trackedFiles,
|
|
73
|
+
},
|
|
74
|
+
value: {
|
|
75
|
+
fingerprint: args.buildId === null
|
|
76
|
+
? null
|
|
77
|
+
: await generateFingerprint({
|
|
78
|
+
buildId: args.buildId,
|
|
79
|
+
content: sourceText,
|
|
80
|
+
}),
|
|
81
|
+
identityPath: record.identityPath,
|
|
82
|
+
rawCode: Buffer.from(transformResult.code).toString('utf8'),
|
|
83
|
+
resolvedPath,
|
|
84
|
+
sourceMap,
|
|
85
|
+
stableUrlPathname,
|
|
86
|
+
trackedFiles,
|
|
87
|
+
unresolvedDependencies,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
error: toTransformFailedError(error, resolvedPath),
|
|
95
|
+
tracking: {
|
|
96
|
+
trackedFiles,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function runLightningTransform(identityPath, code, options) {
|
|
102
|
+
try {
|
|
103
|
+
return transform({
|
|
104
|
+
analyzeDependencies: {
|
|
105
|
+
preserveImports: true,
|
|
106
|
+
},
|
|
107
|
+
code,
|
|
108
|
+
filename: identityPath,
|
|
109
|
+
minify: options.minify,
|
|
110
|
+
sourceMap: options.sourceMap,
|
|
111
|
+
targets: options.targets ?? undefined,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw createAssetServerCompilationError(`Failed to transform style ${identityPath}. ${error instanceof Error ? error.message : String(error)}`, {
|
|
116
|
+
cause: error,
|
|
117
|
+
code: 'TRANSFORM_FAILED',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function toTransformFailedError(error, resolvedPath) {
|
|
122
|
+
if (isAssetServerCompilationError(error))
|
|
123
|
+
return error;
|
|
124
|
+
return createAssetServerCompilationError(`Failed to transform style ${resolvedPath}. ${error instanceof Error ? error.message : String(error)}`, {
|
|
125
|
+
cause: error,
|
|
126
|
+
code: 'TRANSFORM_FAILED',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function isNoEntityError(error) {
|
|
130
|
+
return (error instanceof Error && 'code' in error && error.code === 'ENOENT');
|
|
131
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Targets as LightningCssTargets } from 'lightningcss';
|
|
2
|
+
declare const browserTargetNames: readonly ["chrome", "edge", "firefox", "ie", "ios", "opera", "safari", "samsung"];
|
|
3
|
+
export type AssetTargetVersion = `${number}` | `${number}.${number}` | `${number}.${number}.${number}`;
|
|
4
|
+
export type BrowserTargetName = (typeof browserTargetNames)[number];
|
|
5
|
+
export type ResolvedScriptTarget = string[];
|
|
6
|
+
export type ResolvedStyleTarget = LightningCssTargets;
|
|
7
|
+
export interface AssetTarget {
|
|
8
|
+
chrome?: AssetTargetVersion;
|
|
9
|
+
edge?: AssetTargetVersion;
|
|
10
|
+
firefox?: AssetTargetVersion;
|
|
11
|
+
ie?: AssetTargetVersion;
|
|
12
|
+
ios?: AssetTargetVersion;
|
|
13
|
+
opera?: AssetTargetVersion;
|
|
14
|
+
safari?: AssetTargetVersion;
|
|
15
|
+
samsung?: AssetTargetVersion;
|
|
16
|
+
es?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function resolveScriptTarget(target: AssetTarget | undefined): ResolvedScriptTarget | undefined;
|
|
19
|
+
export declare function resolveStyleTarget(target: AssetTarget | undefined): ResolvedStyleTarget | undefined;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target.d.ts","sourceRoot":"","sources":["../../src/lib/target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAElE,QAAA,MAAM,kBAAkB,mFASd,CAAA;AAeV,MAAM,MAAM,kBAAkB,GAC1B,GAAG,MAAM,EAAE,GACX,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAA;AACnC,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA;AACnE,MAAM,MAAM,oBAAoB,GAAG,MAAM,EAAE,CAAA;AAC3C,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAA;AAErD,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,IAAI,CAAC,EAAE,kBAAkB,CAAA;IACzB,OAAO,CAAC,EAAE,kBAAkB,CAAA;IAC5B,EAAE,CAAC,EAAE,kBAAkB,CAAA;IACvB,GAAG,CAAC,EAAE,kBAAkB,CAAA;IACxB,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,OAAO,CAAC,EAAE,kBAAkB,CAAA;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAMD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,oBAAoB,GAAG,SAAS,CAgBlC;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,mBAAmB,GAAG,SAAS,CAajC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const browserTargetNames = [
|
|
2
|
+
'chrome',
|
|
3
|
+
'edge',
|
|
4
|
+
'firefox',
|
|
5
|
+
'ie',
|
|
6
|
+
'ios',
|
|
7
|
+
'opera',
|
|
8
|
+
'safari',
|
|
9
|
+
'samsung',
|
|
10
|
+
];
|
|
11
|
+
const browserTargetNameSet = new Set(browserTargetNames);
|
|
12
|
+
const lightningCssTargetNameByBrowserTargetName = {
|
|
13
|
+
chrome: 'chrome',
|
|
14
|
+
edge: 'edge',
|
|
15
|
+
firefox: 'firefox',
|
|
16
|
+
ie: 'ie',
|
|
17
|
+
ios: 'ios_saf',
|
|
18
|
+
opera: 'opera',
|
|
19
|
+
safari: 'safari',
|
|
20
|
+
samsung: 'samsung',
|
|
21
|
+
};
|
|
22
|
+
export function resolveScriptTarget(target) {
|
|
23
|
+
let resolvedTarget = normalizeScriptTargetObject(target, 'target');
|
|
24
|
+
if (!resolvedTarget)
|
|
25
|
+
return undefined;
|
|
26
|
+
let oxcTarget = [];
|
|
27
|
+
if (resolvedTarget.es) {
|
|
28
|
+
oxcTarget.push(resolvedTarget.es);
|
|
29
|
+
}
|
|
30
|
+
for (let browserTargetName of browserTargetNames) {
|
|
31
|
+
let version = resolvedTarget[browserTargetName];
|
|
32
|
+
if (version == null)
|
|
33
|
+
continue;
|
|
34
|
+
oxcTarget.push(`${browserTargetName}${version}`);
|
|
35
|
+
}
|
|
36
|
+
return oxcTarget;
|
|
37
|
+
}
|
|
38
|
+
export function resolveStyleTarget(target) {
|
|
39
|
+
let resolvedTarget = normalizeStyleTargetObject(target, 'target');
|
|
40
|
+
if (!resolvedTarget)
|
|
41
|
+
return undefined;
|
|
42
|
+
let lightningCssTargets = {};
|
|
43
|
+
for (let browserTargetName of browserTargetNames) {
|
|
44
|
+
let version = resolvedTarget[browserTargetName];
|
|
45
|
+
if (version == null)
|
|
46
|
+
continue;
|
|
47
|
+
lightningCssTargets[lightningCssTargetNameByBrowserTargetName[browserTargetName]] =
|
|
48
|
+
toLightningCssTargetVersion(version);
|
|
49
|
+
}
|
|
50
|
+
return lightningCssTargets;
|
|
51
|
+
}
|
|
52
|
+
function normalizeScriptTargetObject(target, optionPath) {
|
|
53
|
+
if (target == null)
|
|
54
|
+
return undefined;
|
|
55
|
+
if (!isPlainObject(target)) {
|
|
56
|
+
throw new TypeError(`${optionPath} must be an object`);
|
|
57
|
+
}
|
|
58
|
+
let normalizedTarget = {};
|
|
59
|
+
for (let [key, value] of Object.entries(target)) {
|
|
60
|
+
if (key === 'es') {
|
|
61
|
+
normalizedTarget.es = normalizeScriptTargetVersion(value, `${optionPath}.es`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!browserTargetNameSet.has(key)) {
|
|
65
|
+
throw new TypeError(`${optionPath}.${key} is not a supported target`);
|
|
66
|
+
}
|
|
67
|
+
normalizedTarget[key] = normalizeBrowserTargetVersion(value, `${optionPath}.${key}`);
|
|
68
|
+
}
|
|
69
|
+
return Object.keys(normalizedTarget).length === 0 ? undefined : normalizedTarget;
|
|
70
|
+
}
|
|
71
|
+
function normalizeStyleTargetObject(target, optionPath) {
|
|
72
|
+
if (target == null)
|
|
73
|
+
return undefined;
|
|
74
|
+
if (!isPlainObject(target)) {
|
|
75
|
+
throw new TypeError(`${optionPath} must be an object`);
|
|
76
|
+
}
|
|
77
|
+
let normalizedTarget = {};
|
|
78
|
+
for (let [key, value] of Object.entries(target)) {
|
|
79
|
+
if (key === 'es') {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!browserTargetNameSet.has(key)) {
|
|
83
|
+
throw new TypeError(`${optionPath}.${key} is not a supported target`);
|
|
84
|
+
}
|
|
85
|
+
normalizedTarget[key] = normalizeBrowserTargetVersion(value, `${optionPath}.${key}`);
|
|
86
|
+
}
|
|
87
|
+
return Object.keys(normalizedTarget).length === 0 ? undefined : normalizedTarget;
|
|
88
|
+
}
|
|
89
|
+
function normalizeScriptTargetVersion(value, optionPath) {
|
|
90
|
+
if (typeof value !== 'string') {
|
|
91
|
+
throw new TypeError(`${optionPath} must be a string`);
|
|
92
|
+
}
|
|
93
|
+
let normalizedValue = value.trim();
|
|
94
|
+
if (normalizedValue.length === 0) {
|
|
95
|
+
throw new TypeError(`${optionPath} must be a non-empty string`);
|
|
96
|
+
}
|
|
97
|
+
if (!/^\d+$/.test(normalizedValue)) {
|
|
98
|
+
throw new TypeError(`${optionPath} must use a single numeric year like "2020"`);
|
|
99
|
+
}
|
|
100
|
+
if (!/^\d{4}$/.test(normalizedValue) || Number(normalizedValue) < 2015) {
|
|
101
|
+
throw new TypeError(`${optionPath} must use a four-digit year of 2015 or higher`);
|
|
102
|
+
}
|
|
103
|
+
return `es${normalizedValue}`;
|
|
104
|
+
}
|
|
105
|
+
function normalizeBrowserTargetVersion(value, optionPath) {
|
|
106
|
+
if (typeof value !== 'string') {
|
|
107
|
+
throw new TypeError(`${optionPath} must be a string`);
|
|
108
|
+
}
|
|
109
|
+
if (value.trim().length === 0) {
|
|
110
|
+
throw new TypeError(`${optionPath} must be a non-empty string`);
|
|
111
|
+
}
|
|
112
|
+
if (!/^\d+(\.\d+){0,2}$/.test(value)) {
|
|
113
|
+
throw new TypeError(`${optionPath} must use "X", "X.Y", or "X.Y.Z" version format`);
|
|
114
|
+
}
|
|
115
|
+
let segments = value.split('.').map(Number);
|
|
116
|
+
if (segments.some((segment) => segment > 255)) {
|
|
117
|
+
throw new TypeError(`${optionPath} must use version components between 0 and 255`);
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function toLightningCssTargetVersion(version) {
|
|
122
|
+
let [major, minor = 0, patch = 0] = version.split('.').map(Number);
|
|
123
|
+
return major * 65536 + minor * 256 + patch;
|
|
124
|
+
}
|
|
125
|
+
function isPlainObject(value) {
|
|
126
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
127
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
type AssetServerWatcherOptions = {
|
|
3
|
+
ignore?: readonly string[];
|
|
4
|
+
onChokidarWatcherCreated?: (watcher: ChokidarWatcher) => void;
|
|
5
|
+
poll?: boolean;
|
|
6
|
+
pollInterval?: number;
|
|
7
|
+
onFileEvent(filePath: string, event: AssetServerWatchEvent): Promise<void>;
|
|
8
|
+
rootDir: string;
|
|
9
|
+
};
|
|
10
|
+
type AssetServerWatchEvent = 'add' | 'change' | 'unlink';
|
|
11
|
+
export type ChokidarWatcher = ReturnType<typeof chokidar.watch>;
|
|
12
|
+
export type AssetServerWatcher = {
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
getWatchedTargets(): readonly string[];
|
|
15
|
+
updateWatchedDirectories(delta: {
|
|
16
|
+
add: readonly string[];
|
|
17
|
+
remove: readonly string[];
|
|
18
|
+
}): void;
|
|
19
|
+
};
|
|
20
|
+
export declare function createAssetServerWatcher(options: AssetServerWatcherOptions): AssetServerWatcher;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/lib/watch.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAI/B,KAAK,yBAAyB,GAAG;IAC/B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,qBAAqB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;AACxD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;AAE/D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAAA;IACtC,wBAAwB,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAA;CAC7F,CAAA;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAmD/F"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import { getFilePathDirectory, normalizeFilePath } from "./paths.js";
|
|
3
|
+
export function createAssetServerWatcher(options) {
|
|
4
|
+
let watcher = chokidar.watch([], {
|
|
5
|
+
ignoreInitial: true,
|
|
6
|
+
ignorePermissionErrors: true,
|
|
7
|
+
...resolveChokidarWatchOptions(options),
|
|
8
|
+
});
|
|
9
|
+
options.onChokidarWatcherCreated?.(watcher);
|
|
10
|
+
let watchedDirectories = new Set();
|
|
11
|
+
let watchedTargets = new Set();
|
|
12
|
+
for (let event of ['add', 'change', 'unlink']) {
|
|
13
|
+
watcher.on(event, (filePath) => {
|
|
14
|
+
options.onFileEvent(filePath, event);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
watcher.on('error', (error) => {
|
|
18
|
+
console.error('Asset server file system watcher encountered an error.', error);
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
async close() {
|
|
22
|
+
await watcher.close();
|
|
23
|
+
},
|
|
24
|
+
getWatchedTargets() {
|
|
25
|
+
return [...watchedTargets];
|
|
26
|
+
},
|
|
27
|
+
updateWatchedDirectories(delta) {
|
|
28
|
+
let nextWatchedDirectories = new Set(watchedDirectories);
|
|
29
|
+
for (let directory of delta.add) {
|
|
30
|
+
nextWatchedDirectories.add(directory);
|
|
31
|
+
}
|
|
32
|
+
for (let directory of delta.remove) {
|
|
33
|
+
nextWatchedDirectories.delete(directory);
|
|
34
|
+
}
|
|
35
|
+
let nextTargets = getWatchTargetsForDirectories(options.rootDir, [...nextWatchedDirectories]);
|
|
36
|
+
let targetsToAdd = [...nextTargets].filter((target) => !watchedTargets.has(target));
|
|
37
|
+
let targetsToRemove = [...watchedTargets].filter((target) => !nextTargets.has(target));
|
|
38
|
+
if (targetsToRemove.length > 0) {
|
|
39
|
+
watcher.unwatch(targetsToRemove);
|
|
40
|
+
}
|
|
41
|
+
if (targetsToAdd.length > 0) {
|
|
42
|
+
watcher.add(targetsToAdd);
|
|
43
|
+
}
|
|
44
|
+
watchedDirectories = nextWatchedDirectories;
|
|
45
|
+
watchedTargets = nextTargets;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function resolveChokidarWatchOptions(options) {
|
|
50
|
+
return {
|
|
51
|
+
awaitWriteFinish: {
|
|
52
|
+
pollInterval: 10,
|
|
53
|
+
stabilityThreshold: 10,
|
|
54
|
+
},
|
|
55
|
+
depth: 0,
|
|
56
|
+
ignored: ['**/.git/**', ...(options.ignore ?? [])],
|
|
57
|
+
interval: options.pollInterval ?? 100,
|
|
58
|
+
usePolling: options.poll ?? false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function getWatchTargetsForDirectories(rootDir, directories) {
|
|
62
|
+
let normalizedRootDir = normalizeFilePath(rootDir);
|
|
63
|
+
let targets = new Set();
|
|
64
|
+
let configAncestors = new Set();
|
|
65
|
+
for (let directory of directories) {
|
|
66
|
+
let normalizedDirectory = normalizeFilePath(directory).replace(/\/+$/, '');
|
|
67
|
+
targets.add(normalizedDirectory);
|
|
68
|
+
if (!isSameOrDescendantPath(normalizedDirectory, normalizedRootDir))
|
|
69
|
+
continue;
|
|
70
|
+
for (let ancestor of getAncestorPaths(normalizedDirectory, normalizedRootDir)) {
|
|
71
|
+
configAncestors.add(ancestor);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (let ancestor of configAncestors) {
|
|
75
|
+
targets.add(ancestor);
|
|
76
|
+
}
|
|
77
|
+
return targets;
|
|
78
|
+
}
|
|
79
|
+
function getAncestorPaths(directoryPath, rootDir) {
|
|
80
|
+
let ancestors = [];
|
|
81
|
+
let currentDirectory = directoryPath;
|
|
82
|
+
while (isSameOrDescendantPath(currentDirectory, rootDir)) {
|
|
83
|
+
ancestors.push(currentDirectory);
|
|
84
|
+
if (currentDirectory === rootDir)
|
|
85
|
+
break;
|
|
86
|
+
let parentDirectory = getFilePathDirectory(currentDirectory);
|
|
87
|
+
if (parentDirectory === currentDirectory)
|
|
88
|
+
break;
|
|
89
|
+
currentDirectory = parentDirectory;
|
|
90
|
+
}
|
|
91
|
+
return ancestors;
|
|
92
|
+
}
|
|
93
|
+
function isSameOrDescendantPath(filePath, directoryPath) {
|
|
94
|
+
let normalizedDirectoryPath = directoryPath.replace(/\/+$/, '');
|
|
95
|
+
return filePath === normalizedDirectoryPath || filePath.startsWith(`${normalizedDirectoryPath}/`);
|
|
96
|
+
}
|