@remix-run/assets 0.0.0 → 0.1.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 +319 -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 +137 -0
- package/dist/lib/asset-server.d.ts.map +1 -0
- package/dist/lib/asset-server.js +242 -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 +43 -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/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 +435 -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 +60 -0
- package/dist/lib/scripts/resolve.d.ts.map +1 -0
- package/dist/lib/scripts/resolve.js +230 -0
- package/dist/lib/scripts/store.d.ts +40 -0
- package/dist/lib/scripts/store.d.ts.map +1 -0
- package/dist/lib/scripts/store.js +228 -0
- package/dist/lib/scripts/transform.d.ts +62 -0
- package/dist/lib/scripts/transform.d.ts.map +1 -0
- package/dist/lib/scripts/transform.js +362 -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 +56 -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 +50 -12
- package/src/assets.ts +2 -0
- package/src/lib/access.ts +24 -0
- package/src/lib/asset-server.ts +415 -0
- package/src/lib/compilation-error.ts +61 -0
- package/src/lib/file-matcher.ts +62 -0
- package/src/lib/fingerprint.ts +65 -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 +622 -0
- package/src/lib/scripts/emit.ts +122 -0
- package/src/lib/scripts/resolve.ts +422 -0
- package/src/lib/scripts/store.ts +327 -0
- package/src/lib/scripts/transform.ts +594 -0
- package/src/lib/source-maps.ts +68 -0
- package/src/lib/watch.ts +136 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { IfNoneMatch } from '@remix-run/headers';
|
|
6
|
+
import { createAssetServerCompilationError } from "../compilation-error.js";
|
|
7
|
+
import { createFileMatcher } from "../file-matcher.js";
|
|
8
|
+
import { formatFingerprintedPathname, getFingerprintRequestCacheControl, parseFingerprintSuffix, } from "../fingerprint.js";
|
|
9
|
+
import { emitResolvedModule } from "./emit.js";
|
|
10
|
+
import { normalizeFilePath, resolveFilePath } from "../paths.js";
|
|
11
|
+
import { resolveModule, resolverExtensionAlias, resolverExtensions, supportedScriptExtensions, } from "./resolve.js";
|
|
12
|
+
import { createModuleStore } from "./store.js";
|
|
13
|
+
import { createTsconfigTransformOptionsResolver, transformModule } from "./transform.js";
|
|
14
|
+
import { ResolverFactory } from 'oxc-resolver';
|
|
15
|
+
const supportedScriptExtensionSet = new Set(supportedScriptExtensions);
|
|
16
|
+
const preloadConcurrency = Math.max(1, Math.min(8, os.availableParallelism() - 1));
|
|
17
|
+
export function createModuleCompiler(options) {
|
|
18
|
+
let resolvedOptions = {
|
|
19
|
+
...options,
|
|
20
|
+
externalSet: new Set(options.external),
|
|
21
|
+
watchIgnoreMatchers: (options.watchIgnore ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir)),
|
|
22
|
+
};
|
|
23
|
+
let store = createModuleStore({
|
|
24
|
+
onWatchDirectoriesChange: options.onWatchDirectoriesChange,
|
|
25
|
+
});
|
|
26
|
+
let tsconfigTransformOptionsResolver = createTsconfigTransformOptionsResolver();
|
|
27
|
+
let resolverFactory = new ResolverFactory({
|
|
28
|
+
aliasFields: [['browser']],
|
|
29
|
+
conditionNames: ['browser', 'import', 'module', 'default'],
|
|
30
|
+
extensionAlias: resolverExtensionAlias,
|
|
31
|
+
extensions: resolverExtensions,
|
|
32
|
+
mainFields: ['browser', 'module', 'main'],
|
|
33
|
+
tsconfig: 'auto',
|
|
34
|
+
});
|
|
35
|
+
let resolveInFlightByCacheKey = new Map();
|
|
36
|
+
let emitInFlightByCacheKey = new Map();
|
|
37
|
+
let transformArgs = {
|
|
38
|
+
buildId: resolvedOptions.buildId ?? null,
|
|
39
|
+
define: resolvedOptions.define ?? null,
|
|
40
|
+
externalSet: resolvedOptions.externalSet,
|
|
41
|
+
isWatchIgnored,
|
|
42
|
+
minify: resolvedOptions.minify,
|
|
43
|
+
resolveActualPath,
|
|
44
|
+
routes: resolvedOptions.routes,
|
|
45
|
+
sourceMapSourcePaths: resolvedOptions.sourceMapSourcePaths,
|
|
46
|
+
sourceMaps: resolvedOptions.sourceMaps ?? null,
|
|
47
|
+
target: resolvedOptions.target ?? null,
|
|
48
|
+
tsconfigTransformOptionsResolver,
|
|
49
|
+
};
|
|
50
|
+
let resolveArgs = {
|
|
51
|
+
isAllowed: resolvedOptions.isAllowed,
|
|
52
|
+
isWatchIgnored,
|
|
53
|
+
resolveModulePath,
|
|
54
|
+
resolverFactory,
|
|
55
|
+
routes: resolvedOptions.routes,
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
async getModule(filePath, getOptions) {
|
|
59
|
+
let resolvedModule = resolveServedModuleOrThrow(resolveInputFilePath(filePath));
|
|
60
|
+
let record = store.get(resolvedModule.identityPath);
|
|
61
|
+
let notModified = getNotModifiedModule(record, getOptions);
|
|
62
|
+
if (notModified)
|
|
63
|
+
return notModified;
|
|
64
|
+
let emitted = await getOrCreateEmittedModule(record);
|
|
65
|
+
return {
|
|
66
|
+
type: 'module',
|
|
67
|
+
module: toModuleCompileResult(emitted),
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
async getPreloadUrls(filePath) {
|
|
71
|
+
let resolvedEntries = [];
|
|
72
|
+
let seen = new Set();
|
|
73
|
+
for (let resolvedModule of (Array.isArray(filePath) ? filePath : [filePath]).map((nextPath) => resolveServedModuleOrThrow(resolveInputFilePath(nextPath)))) {
|
|
74
|
+
if (seen.has(resolvedModule.identityPath))
|
|
75
|
+
continue;
|
|
76
|
+
seen.add(resolvedModule.identityPath);
|
|
77
|
+
resolvedEntries.push(resolvedModule.identityPath);
|
|
78
|
+
}
|
|
79
|
+
let visited = new Set(resolvedEntries);
|
|
80
|
+
let queue = [...resolvedEntries];
|
|
81
|
+
let urls = [];
|
|
82
|
+
while (queue.length > 0) {
|
|
83
|
+
let frontier = queue;
|
|
84
|
+
queue = [];
|
|
85
|
+
let resolvedModules = await getOrCreateResolvedModules(frontier.map((identityPath) => store.get(identityPath)));
|
|
86
|
+
for (let resolvedModule of resolvedModules) {
|
|
87
|
+
urls.push(getServedUrlForResolvedModule(resolvedModule));
|
|
88
|
+
for (let dep of resolvedModule.deps) {
|
|
89
|
+
if (visited.has(dep))
|
|
90
|
+
continue;
|
|
91
|
+
visited.add(dep);
|
|
92
|
+
queue.push(dep);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return urls;
|
|
97
|
+
},
|
|
98
|
+
async getHref(filePath) {
|
|
99
|
+
let resolvedModule = resolveServedModuleOrThrow(resolveInputFilePath(filePath));
|
|
100
|
+
return getServedUrl(resolvedModule.identityPath);
|
|
101
|
+
},
|
|
102
|
+
async handleFileEvent(filePath, event) {
|
|
103
|
+
let normalizedFilePath = normalizeFilePath(filePath);
|
|
104
|
+
if (isWatchIgnored(normalizedFilePath))
|
|
105
|
+
return;
|
|
106
|
+
if (shouldClearResolverCacheForFileEvent(normalizedFilePath, event)) {
|
|
107
|
+
resolverFactory.clearCache();
|
|
108
|
+
}
|
|
109
|
+
if (isTsconfigPath(normalizedFilePath)) {
|
|
110
|
+
tsconfigTransformOptionsResolver.clear();
|
|
111
|
+
store.invalidateAll();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (isPackageJsonPath(normalizedFilePath)) {
|
|
115
|
+
store.invalidateAll();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
store.invalidateForFileEvent(normalizedFilePath, event);
|
|
119
|
+
},
|
|
120
|
+
parseRequestPathname(pathname) {
|
|
121
|
+
let parsedPathname = parseServedPathname(pathname);
|
|
122
|
+
let filePath = resolvedOptions.routes.resolveUrlPathname(parsedPathname.stablePathname);
|
|
123
|
+
if (!filePath)
|
|
124
|
+
return null;
|
|
125
|
+
if (resolvedOptions.fingerprintModules && parsedPathname.requestedFingerprint === null)
|
|
126
|
+
return null;
|
|
127
|
+
return {
|
|
128
|
+
cacheControl: getFingerprintRequestCacheControl(parsedPathname.requestedFingerprint),
|
|
129
|
+
filePath,
|
|
130
|
+
isSourceMapRequest: parsedPathname.isSourceMapRequest,
|
|
131
|
+
requestedFingerprint: parsedPathname.requestedFingerprint,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
function resolveInputFilePath(filePath) {
|
|
136
|
+
if (filePath.startsWith('file://')) {
|
|
137
|
+
return normalizeFilePath(fileURLToPath(new URL(filePath)));
|
|
138
|
+
}
|
|
139
|
+
if (filePath.includes('://')) {
|
|
140
|
+
throw new TypeError(`Expected a file path or file:// URL, received "${filePath}"`);
|
|
141
|
+
}
|
|
142
|
+
return resolveFilePath(resolvedOptions.rootDir, filePath);
|
|
143
|
+
}
|
|
144
|
+
function resolveServedModuleOrThrow(absolutePath) {
|
|
145
|
+
let resolvedModule = resolveModulePath(absolutePath);
|
|
146
|
+
if (!resolvedModule) {
|
|
147
|
+
throw createAssetServerCompilationError(`Module not found: ${absolutePath}`, {
|
|
148
|
+
code: 'MODULE_NOT_FOUND',
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (!resolvedOptions.isAllowed(resolvedModule.identityPath)) {
|
|
152
|
+
throw createAssetServerCompilationError(`Module is not allowed: ${resolvedModule.identityPath}`, {
|
|
153
|
+
code: 'MODULE_NOT_ALLOWED',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return resolvedModule;
|
|
157
|
+
}
|
|
158
|
+
function getNotModifiedModule(record, options) {
|
|
159
|
+
let current = getNotModifiedResult(record.emitted, options);
|
|
160
|
+
if (current)
|
|
161
|
+
return current;
|
|
162
|
+
if (!record.staleEmittedSnapshot || !isModuleSnapshotFresh(record.staleEmittedSnapshot)) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return getNotModifiedResult(record.staleEmitted, options);
|
|
166
|
+
}
|
|
167
|
+
async function getOrCreateResolvedModules(records) {
|
|
168
|
+
return mapWithConcurrency(records, preloadConcurrency, (record) => getOrCreateResolvedModule(record));
|
|
169
|
+
}
|
|
170
|
+
async function getOrCreateResolvedModule(record) {
|
|
171
|
+
if (record.resolved)
|
|
172
|
+
return record.resolved;
|
|
173
|
+
let cacheKey = getRecordCacheKey(record);
|
|
174
|
+
let existing = resolveInFlightByCacheKey.get(cacheKey);
|
|
175
|
+
if (existing)
|
|
176
|
+
return existing;
|
|
177
|
+
let promise = (async () => {
|
|
178
|
+
let startedVersion = record.invalidationVersion;
|
|
179
|
+
let transformedModule = await getOrCreateTransformedModule(record);
|
|
180
|
+
if (resolvedOptions.watchMode &&
|
|
181
|
+
transformedModule.unresolvedImports.some((unresolved) => isBareImportSpecifier(unresolved.specifier))) {
|
|
182
|
+
resolverFactory.clearCache();
|
|
183
|
+
}
|
|
184
|
+
let resolveModuleResult = await resolveModule(record, transformedModule, resolveArgs);
|
|
185
|
+
if (!resolveModuleResult.ok) {
|
|
186
|
+
if (isFresh(record, startedVersion)) {
|
|
187
|
+
store.setResolveFailure(record.identityPath, resolveModuleResult.tracking);
|
|
188
|
+
}
|
|
189
|
+
throw resolveModuleResult.error;
|
|
190
|
+
}
|
|
191
|
+
if (isFresh(record, startedVersion)) {
|
|
192
|
+
store.setResolved(record.identityPath, resolveModuleResult.value);
|
|
193
|
+
}
|
|
194
|
+
return resolveModuleResult.value;
|
|
195
|
+
})();
|
|
196
|
+
resolveInFlightByCacheKey.set(cacheKey, promise);
|
|
197
|
+
try {
|
|
198
|
+
return await promise;
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
if (resolveInFlightByCacheKey.get(cacheKey) === promise) {
|
|
202
|
+
resolveInFlightByCacheKey.delete(cacheKey);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async function getOrCreateTransformedModule(record) {
|
|
207
|
+
if (record.transformed)
|
|
208
|
+
return record.transformed;
|
|
209
|
+
let startedVersion = record.invalidationVersion;
|
|
210
|
+
let transformModuleResult = await transformModule(record, transformArgs);
|
|
211
|
+
if (!transformModuleResult.ok) {
|
|
212
|
+
if (isFresh(record, startedVersion)) {
|
|
213
|
+
store.setTransformFailure(record.identityPath, {
|
|
214
|
+
trackedFiles: transformModuleResult.trackedFiles,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
throw transformModuleResult.error;
|
|
218
|
+
}
|
|
219
|
+
if (isFresh(record, startedVersion)) {
|
|
220
|
+
store.setTransformed(record.identityPath, transformModuleResult.value);
|
|
221
|
+
}
|
|
222
|
+
return transformModuleResult.value;
|
|
223
|
+
}
|
|
224
|
+
async function getOrCreateEmittedModule(record) {
|
|
225
|
+
if (record.emitted)
|
|
226
|
+
return record.emitted;
|
|
227
|
+
let cacheKey = getRecordCacheKey(record);
|
|
228
|
+
let existing = emitInFlightByCacheKey.get(cacheKey);
|
|
229
|
+
if (existing)
|
|
230
|
+
return existing;
|
|
231
|
+
let promise = (async () => {
|
|
232
|
+
let startedVersion = record.invalidationVersion;
|
|
233
|
+
let resolvedModule = await getOrCreateResolvedModule(record);
|
|
234
|
+
let emitResolvedModuleResult = await emitResolvedModule(resolvedModule, {
|
|
235
|
+
getServedUrl,
|
|
236
|
+
sourceMaps: resolvedOptions.sourceMaps,
|
|
237
|
+
});
|
|
238
|
+
if (!emitResolvedModuleResult.ok) {
|
|
239
|
+
throw emitResolvedModuleResult.error;
|
|
240
|
+
}
|
|
241
|
+
if (isFresh(record, startedVersion)) {
|
|
242
|
+
store.setEmitted(record.identityPath, emitResolvedModuleResult.value, createModuleSnapshot(resolvedModule.trackedFiles));
|
|
243
|
+
}
|
|
244
|
+
return emitResolvedModuleResult.value;
|
|
245
|
+
})();
|
|
246
|
+
emitInFlightByCacheKey.set(cacheKey, promise);
|
|
247
|
+
try {
|
|
248
|
+
return await promise;
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
if (emitInFlightByCacheKey.get(cacheKey) === promise) {
|
|
252
|
+
emitInFlightByCacheKey.delete(cacheKey);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async function getServedUrl(identityPath) {
|
|
257
|
+
return getServedUrlForResolvedModule(await getOrCreateResolvedModule(store.get(identityPath)));
|
|
258
|
+
}
|
|
259
|
+
function getServedUrlForResolvedModule(resolvedModule) {
|
|
260
|
+
return formatFingerprintedPathname(resolvedModule.stableUrlPathname, resolvedOptions.fingerprintModules ? resolvedModule.fingerprint : null);
|
|
261
|
+
}
|
|
262
|
+
function isWatchIgnored(filePath) {
|
|
263
|
+
return resolvedOptions.watchIgnoreMatchers.some((matcher) => matcher(filePath));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function getRecordCacheKey(record) {
|
|
267
|
+
return `${record.identityPath}\0${record.invalidationVersion}`;
|
|
268
|
+
}
|
|
269
|
+
function isFresh(record, version) {
|
|
270
|
+
return record.invalidationVersion === version;
|
|
271
|
+
}
|
|
272
|
+
function getNotModifiedResult(emittedModule, options) {
|
|
273
|
+
if (!emittedModule || options.ifNoneMatch === null)
|
|
274
|
+
return null;
|
|
275
|
+
if (options.requestedFingerprint !== null &&
|
|
276
|
+
emittedModule.fingerprint !== options.requestedFingerprint) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
let asset = getEmittedAssetForRequest(emittedModule, options.isSourceMapRequest);
|
|
280
|
+
if (!asset)
|
|
281
|
+
return null;
|
|
282
|
+
if (!IfNoneMatch.from(options.ifNoneMatch).matches(asset.etag))
|
|
283
|
+
return null;
|
|
284
|
+
return { type: 'not-modified', etag: asset.etag };
|
|
285
|
+
}
|
|
286
|
+
function getEmittedAssetForRequest(emittedModule, isSourceMapRequest) {
|
|
287
|
+
return isSourceMapRequest ? emittedModule.sourceMap : emittedModule.code;
|
|
288
|
+
}
|
|
289
|
+
function createModuleSnapshot(filePaths) {
|
|
290
|
+
let snapshot = new Map();
|
|
291
|
+
for (let filePath of filePaths) {
|
|
292
|
+
let fileSnapshot = getFileSnapshot(filePath);
|
|
293
|
+
if (!fileSnapshot)
|
|
294
|
+
return null;
|
|
295
|
+
snapshot.set(filePath, fileSnapshot);
|
|
296
|
+
}
|
|
297
|
+
return snapshot;
|
|
298
|
+
}
|
|
299
|
+
function isModuleSnapshotFresh(snapshot) {
|
|
300
|
+
for (let [filePath, previous] of snapshot) {
|
|
301
|
+
let current = getFileSnapshot(filePath);
|
|
302
|
+
if (!current)
|
|
303
|
+
return false;
|
|
304
|
+
if (current.mtimeNs !== previous.mtimeNs || current.size !== previous.size)
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
function getFileSnapshot(filePath) {
|
|
310
|
+
try {
|
|
311
|
+
let stats = fs.statSync(filePath, { bigint: true });
|
|
312
|
+
if (!stats.isFile())
|
|
313
|
+
return null;
|
|
314
|
+
return {
|
|
315
|
+
mtimeNs: stats.mtimeNs,
|
|
316
|
+
size: stats.size,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
if (isNoEntityError(error))
|
|
321
|
+
return null;
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function parseServedPathname(pathname) {
|
|
326
|
+
let isSourceMapRequest = pathname.endsWith('.map');
|
|
327
|
+
let pathWithoutMap = isSourceMapRequest ? pathname.slice(0, -4) : pathname;
|
|
328
|
+
let fingerprint = parseFingerprintSuffix(pathWithoutMap);
|
|
329
|
+
return {
|
|
330
|
+
isSourceMapRequest,
|
|
331
|
+
requestedFingerprint: fingerprint.requestedFingerprint,
|
|
332
|
+
stablePathname: fingerprint.pathname,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
336
|
+
if (items.length === 0)
|
|
337
|
+
return [];
|
|
338
|
+
let results = new Array(items.length);
|
|
339
|
+
let nextIndex = 0;
|
|
340
|
+
async function worker() {
|
|
341
|
+
while (nextIndex < items.length) {
|
|
342
|
+
let index = nextIndex++;
|
|
343
|
+
results[index] = await mapper(items[index], index);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
|
|
347
|
+
return results;
|
|
348
|
+
}
|
|
349
|
+
function toModuleCompileResult(emittedModule) {
|
|
350
|
+
return {
|
|
351
|
+
code: emittedModule.code,
|
|
352
|
+
fingerprint: emittedModule.fingerprint,
|
|
353
|
+
sourceMap: emittedModule.sourceMap,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function isPackageJsonPath(filePath) {
|
|
357
|
+
return filePath.endsWith('/package.json');
|
|
358
|
+
}
|
|
359
|
+
function isTsconfigPath(filePath) {
|
|
360
|
+
return /\/tsconfig(?:\..+)?\.json$/.test(filePath);
|
|
361
|
+
}
|
|
362
|
+
function shouldClearResolverCacheForFileEvent(filePath, event) {
|
|
363
|
+
return event !== 'change' || isPackageJsonPath(filePath) || isTsconfigPath(filePath);
|
|
364
|
+
}
|
|
365
|
+
function resolveModulePath(absolutePath) {
|
|
366
|
+
let resolvedPath;
|
|
367
|
+
try {
|
|
368
|
+
resolvedPath = normalizeFilePath(fs.realpathSync(normalizeFilePath(absolutePath)));
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
if (isNoEntityError(error))
|
|
372
|
+
return null;
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
if (!supportedScriptExtensionSet.has(path.extname(resolvedPath).toLowerCase())) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
identityPath: resolvedPath,
|
|
380
|
+
resolvedPath,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function resolveActualPath(identityPath) {
|
|
384
|
+
try {
|
|
385
|
+
return normalizeFilePath(fs.realpathSync(identityPath));
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
if (isNoEntityError(error))
|
|
389
|
+
return null;
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function isBareImportSpecifier(specifier) {
|
|
394
|
+
return (!specifier.startsWith('./') &&
|
|
395
|
+
!specifier.startsWith('../') &&
|
|
396
|
+
!specifier.startsWith('/') &&
|
|
397
|
+
!specifier.startsWith('file:') &&
|
|
398
|
+
!specifier.startsWith('data:') &&
|
|
399
|
+
!specifier.startsWith('http://') &&
|
|
400
|
+
!specifier.startsWith('https://'));
|
|
401
|
+
}
|
|
402
|
+
function isNoEntityError(error) {
|
|
403
|
+
return (error instanceof Error &&
|
|
404
|
+
'code' in error &&
|
|
405
|
+
(error.code === 'ENOENT' ||
|
|
406
|
+
error.code === 'ENOTDIR'));
|
|
407
|
+
}
|
|
408
|
+
export function createResponseForModule(result, options) {
|
|
409
|
+
let body;
|
|
410
|
+
let etag;
|
|
411
|
+
let contentType;
|
|
412
|
+
if (options.isSourceMapRequest) {
|
|
413
|
+
if (!result.sourceMap) {
|
|
414
|
+
return new Response('Not found', { status: 404 });
|
|
415
|
+
}
|
|
416
|
+
body = options.method === 'HEAD' ? null : result.sourceMap.content;
|
|
417
|
+
etag = result.sourceMap.etag;
|
|
418
|
+
contentType = 'application/json; charset=utf-8';
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
body = options.method === 'HEAD' ? null : result.code.content;
|
|
422
|
+
etag = result.code.etag;
|
|
423
|
+
contentType = 'application/javascript; charset=utf-8';
|
|
424
|
+
}
|
|
425
|
+
if (IfNoneMatch.from(options.ifNoneMatch).matches(etag)) {
|
|
426
|
+
return new Response(null, { status: 304, headers: { ETag: etag } });
|
|
427
|
+
}
|
|
428
|
+
return new Response(body, {
|
|
429
|
+
headers: {
|
|
430
|
+
'Cache-Control': options.cacheControl,
|
|
431
|
+
'Content-Type': contentType,
|
|
432
|
+
ETag: etag,
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ResolvedModule } from './resolve.ts';
|
|
2
|
+
import type { AssetServerCompilationError } from '../compilation-error.ts';
|
|
3
|
+
export type EmittedAsset = {
|
|
4
|
+
content: string;
|
|
5
|
+
etag: string;
|
|
6
|
+
};
|
|
7
|
+
export type EmittedModule = {
|
|
8
|
+
code: EmittedAsset;
|
|
9
|
+
fingerprint: string | null;
|
|
10
|
+
importUrls: string[];
|
|
11
|
+
sourceMap: EmittedAsset | null;
|
|
12
|
+
};
|
|
13
|
+
type EmitResult = {
|
|
14
|
+
ok: true;
|
|
15
|
+
value: EmittedModule;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
error: AssetServerCompilationError;
|
|
19
|
+
};
|
|
20
|
+
export declare function emitResolvedModule(resolvedModule: ResolvedModule, options: {
|
|
21
|
+
getServedUrl(identityPath: string): Promise<string>;
|
|
22
|
+
sourceMaps?: 'external' | 'inline';
|
|
23
|
+
}): Promise<EmitResult>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/emit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,UAAU,GACX;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,aAAa,CAAA;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CAAA;AAEL,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE;IACP,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnD,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,GACA,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import MagicString from 'magic-string';
|
|
2
|
+
import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
|
|
3
|
+
import { hashContent } from "../fingerprint.js";
|
|
4
|
+
import { composeSourceMaps } from "../source-maps.js";
|
|
5
|
+
export async function emitResolvedModule(resolvedModule, options) {
|
|
6
|
+
try {
|
|
7
|
+
let importUrls = await Promise.all(resolvedModule.deps.map((depPath) => options.getServedUrl(depPath)));
|
|
8
|
+
let rewriteResult = await rewriteImports(resolvedModule, options);
|
|
9
|
+
let finalCode = rewriteResult.code;
|
|
10
|
+
if (rewriteResult.sourceMap) {
|
|
11
|
+
if (options.sourceMaps === 'inline') {
|
|
12
|
+
let encoded = Buffer.from(rewriteResult.sourceMap).toString('base64');
|
|
13
|
+
finalCode += `\n//# sourceMappingURL=data:application/json;base64,${encoded}`;
|
|
14
|
+
}
|
|
15
|
+
else if (options.sourceMaps === 'external') {
|
|
16
|
+
finalCode += `\n//# sourceMappingURL=${await options.getServedUrl(resolvedModule.identityPath)}.map`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
ok: true,
|
|
21
|
+
value: {
|
|
22
|
+
code: await createEmittedAsset(finalCode),
|
|
23
|
+
fingerprint: resolvedModule.fingerprint,
|
|
24
|
+
importUrls,
|
|
25
|
+
sourceMap: rewriteResult.sourceMap
|
|
26
|
+
? await createEmittedAsset(rewriteResult.sourceMap)
|
|
27
|
+
: null,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
error: toEmitError(error, resolvedModule.identityPath),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function rewriteImports(resolvedModule, options) {
|
|
39
|
+
let rewrittenSource = new MagicString(resolvedModule.rawCode);
|
|
40
|
+
for (let imported of resolvedModule.imports) {
|
|
41
|
+
let url = await options.getServedUrl(imported.depPath);
|
|
42
|
+
rewrittenSource.overwrite(imported.start, imported.end, imported.quote ? `${imported.quote}${url}${imported.quote}` : url);
|
|
43
|
+
}
|
|
44
|
+
let code = rewrittenSource.toString();
|
|
45
|
+
let sourceMap = resolvedModule.sourceMap && resolvedModule.imports.length > 0
|
|
46
|
+
? composeSourceMaps(rewrittenSource.generateMap({ hires: true }).toString(), resolvedModule.sourceMap)
|
|
47
|
+
: resolvedModule.sourceMap;
|
|
48
|
+
return { code, sourceMap };
|
|
49
|
+
}
|
|
50
|
+
async function createEmittedAsset(content) {
|
|
51
|
+
return {
|
|
52
|
+
content,
|
|
53
|
+
etag: `W/"${await hashContent(content)}"`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function toEmitError(error, identityPath) {
|
|
57
|
+
if (isAssetServerCompilationError(error))
|
|
58
|
+
return error;
|
|
59
|
+
return createAssetServerCompilationError(`Failed to emit module ${identityPath}. ${error instanceof Error ? error.message : String(error)}`, {
|
|
60
|
+
cause: error,
|
|
61
|
+
code: 'MODULE_EMIT_FAILED',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ResolverFactory } from 'oxc-resolver';
|
|
2
|
+
import type { AssetServerCompilationError } from '../compilation-error.ts';
|
|
3
|
+
import type { CompiledRoutes } from '../routes.ts';
|
|
4
|
+
import type { ModuleRecord } from './store.ts';
|
|
5
|
+
import type { ResolveModuleResult, TransformedModule } from './transform.ts';
|
|
6
|
+
export declare const resolverExtensionAlias: {
|
|
7
|
+
'.js': string[];
|
|
8
|
+
'.jsx': string[];
|
|
9
|
+
'.mjs': string[];
|
|
10
|
+
};
|
|
11
|
+
export declare const resolverExtensions: string[];
|
|
12
|
+
export declare const supportedScriptExtensions: string[];
|
|
13
|
+
type ResolvedImport = {
|
|
14
|
+
depPath: string;
|
|
15
|
+
end: number;
|
|
16
|
+
quote?: '"' | "'" | '`';
|
|
17
|
+
start: number;
|
|
18
|
+
};
|
|
19
|
+
type RelativeImportResolution = {
|
|
20
|
+
candidatePaths: readonly string[];
|
|
21
|
+
candidatePrefixes: readonly string[];
|
|
22
|
+
specifier: string;
|
|
23
|
+
};
|
|
24
|
+
export type TrackedResolution = RelativeImportResolution & {
|
|
25
|
+
resolvedIdentityPath: string | null;
|
|
26
|
+
};
|
|
27
|
+
export type ResolvedModule = {
|
|
28
|
+
deps: string[];
|
|
29
|
+
fingerprint: string | null;
|
|
30
|
+
identityPath: string;
|
|
31
|
+
imports: ResolvedImport[];
|
|
32
|
+
trackedFiles: string[];
|
|
33
|
+
trackedResolutions: TrackedResolution[];
|
|
34
|
+
rawCode: string;
|
|
35
|
+
resolvedPath: string;
|
|
36
|
+
sourceMap: string | null;
|
|
37
|
+
stableUrlPathname: string;
|
|
38
|
+
};
|
|
39
|
+
export type ResolutionFailureState = {
|
|
40
|
+
trackedFiles: readonly string[];
|
|
41
|
+
trackedResolutions: readonly TrackedResolution[];
|
|
42
|
+
};
|
|
43
|
+
type ResolveResult = {
|
|
44
|
+
ok: true;
|
|
45
|
+
value: ResolvedModule;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
error: AssetServerCompilationError;
|
|
49
|
+
tracking: ResolutionFailureState;
|
|
50
|
+
};
|
|
51
|
+
export type ResolveArgs = {
|
|
52
|
+
isAllowed(absolutePath: string): boolean;
|
|
53
|
+
isWatchIgnored(filePath: string): boolean;
|
|
54
|
+
resolveModulePath(absolutePath: string): ResolveModuleResult | null;
|
|
55
|
+
resolverFactory: ResolverFactory;
|
|
56
|
+
routes: CompiledRoutes;
|
|
57
|
+
};
|
|
58
|
+
export declare function resolveModule(record: ModuleRecord, transformed: TransformedModule, args: ResolveArgs): Promise<ResolveResult>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAMnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,eAAO,MAAM,sBAAsB;;;;CAIC,CAAA;AAEpC,eAAO,MAAM,kBAAkB,UAAiD,CAAA;AAChF,eAAO,MAAM,yBAAyB,UAAiD,CAAA;AAGvF,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,wBAAwB,GAAG;IAC9B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,GAAG;IACzD,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,kBAAkB,EAAE,iBAAiB,EAAE,CAAA;IACvC,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,kBAAkB,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACjD,CAAA;AAED,KAAK,aAAa,GACd;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,cAAc,CAAA;CACtB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;IAClC,QAAQ,EAAE,sBAAsB,CAAA;CACjC,CAAA;AAEL,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAAA;IACnE,eAAe,EAAE,eAAe,CAAA;IAChC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAQD,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,iBAAiB,EAC9B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAyIxB"}
|