@atlaspack/core 2.16.2-canary.410 → 2.16.2-canary.412

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.
@@ -44,7 +44,6 @@ const diagnostic_1 = __importStar(require("@atlaspack/diagnostic"));
44
44
  const stream_1 = require("stream");
45
45
  const nullthrows_1 = __importDefault(require("nullthrows"));
46
46
  const path_1 = __importDefault(require("path"));
47
- const url_1 = __importDefault(require("url"));
48
47
  const rust_1 = require("@atlaspack/rust");
49
48
  const Bundle_1 = require("./public/Bundle");
50
49
  const BundleGraph_1 = __importStar(require("./public/BundleGraph"));
@@ -58,6 +57,7 @@ const DevDepRequest_1 = require("./requests/DevDepRequest");
58
57
  const assetUtils_1 = require("./assetUtils");
59
58
  const utils_2 = require("./utils");
60
59
  const DevDepRequest_2 = require("./requests/DevDepRequest");
60
+ const WriteBundleRequest_1 = require("./requests/WriteBundleRequest");
61
61
  const profiler_1 = require("@atlaspack/profiler");
62
62
  const EnvironmentManager_1 = require("./EnvironmentManager");
63
63
  const feature_flags_1 = require("@atlaspack/feature-flags");
@@ -330,48 +330,18 @@ class PackagerRunner {
330
330
  return optimized;
331
331
  }
332
332
  async generateSourceMap(bundle, map) {
333
- // sourceRoot should be a relative path between outDir and rootDir for node.js targets
333
+ let sourceRoot = (0, WriteBundleRequest_1.computeSourceMapRoot)(bundle, this.options);
334
+ let inlineSources = sourceRoot === undefined;
334
335
  let filePath = (0, projectPath_1.joinProjectPath)(bundle.target.distDir, (0, nullthrows_1.default)(bundle.name));
335
336
  let fullPath = (0, projectPath_1.fromProjectPath)(this.options.projectRoot, filePath);
336
- let sourceRoot = path_1.default.relative(path_1.default.dirname(fullPath), this.options.projectRoot);
337
- let inlineSources = false;
338
- const bundleEnv = (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env);
339
- if (bundle.target) {
340
- const bundleTargetEnv = (0, EnvironmentManager_1.fromEnvironmentId)(bundle.target.env);
341
- if (bundleEnv.sourceMap && bundleEnv.sourceMap.sourceRoot !== undefined) {
342
- sourceRoot = bundleEnv.sourceMap.sourceRoot;
343
- }
344
- else if (this.options.serveOptions &&
345
- bundleTargetEnv.context === 'browser') {
346
- sourceRoot = '/__parcel_source_root';
347
- }
348
- if (bundleEnv.sourceMap &&
349
- bundleEnv.sourceMap.inlineSources !== undefined) {
350
- inlineSources = bundleEnv.sourceMap.inlineSources;
351
- }
352
- else if (bundleTargetEnv.context !== 'node') {
353
- // inlining should only happen in production for browser targets by default
354
- inlineSources = this.options.mode === 'production';
355
- }
356
- }
357
337
  let mapFilename = fullPath + '.map';
338
+ const bundleEnv = (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env);
358
339
  let isInlineMap = bundleEnv.sourceMap && bundleEnv.sourceMap.inline;
359
- if ((0, feature_flags_1.getFeatureFlag)('omitSourcesContentInMemory') && !isInlineMap) {
360
- if (!(bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources === false)) {
361
- /*
362
- We're omitting sourcesContent during transformation to allow GC to run.
363
- Ensure sources are still inlined into the final source maps written to disk. UNLESS the user explicitly disabled inlineSources.
364
- */
365
- inlineSources = true;
366
- }
367
- }
368
340
  let stringified = await map.stringify({
369
341
  file: path_1.default.basename(mapFilename),
370
342
  fs: this.options.inputFS,
371
343
  rootDir: this.options.projectRoot,
372
- sourceRoot: !inlineSources
373
- ? url_1.default.format(url_1.default.parse(sourceRoot + '/'))
374
- : undefined,
344
+ sourceRoot,
375
345
  inlineSources,
376
346
  format: isInlineMap ? 'inline' : 'string',
377
347
  });
@@ -37,9 +37,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.default = createWriteBundleRequest;
40
+ exports.applyReplacementsToSourceMap = applyReplacementsToSourceMap;
41
+ exports.computeSourceMapRoot = computeSourceMapRoot;
40
42
  const constants_1 = require("../constants");
41
43
  const nullthrows_1 = __importDefault(require("nullthrows"));
42
44
  const path_1 = __importDefault(require("path"));
45
+ const url_1 = __importDefault(require("url"));
43
46
  const Bundle_1 = require("../public/Bundle");
44
47
  const utils_1 = require("@atlaspack/utils");
45
48
  const stream_1 = require("stream");
@@ -53,8 +56,10 @@ const profiler_1 = require("@atlaspack/profiler");
53
56
  const RequestTracker_1 = require("../RequestTracker");
54
57
  const feature_flags_1 = require("@atlaspack/feature-flags");
55
58
  const EnvironmentManager_1 = require("../EnvironmentManager");
59
+ const source_map_1 = __importDefault(require("@atlaspack/source-map"));
56
60
  const HASH_REF_PREFIX_LEN = constants_1.HASH_REF_PREFIX.length;
57
61
  const BOUNDARY_LENGTH = constants_1.HASH_REF_PREFIX.length + 32 - 1;
62
+ const HASH_REF_PLACEHOLDER_LEN = HASH_REF_PREFIX_LEN + constants_1.HASH_REF_HASH_LEN;
58
63
  /**
59
64
  * Writes a bundle to the dist directory, replacing hash references with the final content hashes.
60
65
  */
@@ -125,15 +130,43 @@ async function run({ input, options, api }) {
125
130
  let config = (0, AtlaspackConfigRequest_1.getCachedAtlaspackConfig)(configResult, options);
126
131
  let { devDeps, invalidDevDeps } = await (0, DevDepRequest_1.getDevDepRequests)(api);
127
132
  (0, DevDepRequest_1.invalidateDevDeps)(invalidDevDeps, options, config);
128
- await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api);
133
+ const bundleReplacements = (0, feature_flags_1.getFeatureFlag)('fixSourceMapHashRefs')
134
+ ? []
135
+ : undefined;
136
+ await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api, bundleReplacements);
129
137
  const hasSourceMap = (0, feature_flags_1.getFeatureFlag)('cachePerformanceImprovements')
130
138
  ? await options.cache.hasLargeBlob(mapKey)
131
139
  : await options.cache.has(mapKey);
132
140
  if (mapKey && env.sourceMap && !env.sourceMap.inline && hasSourceMap) {
133
- const mapEntry = (0, feature_flags_1.getFeatureFlag)('cachePerformanceImprovements')
134
- ? await options.cache.getLargeBlob(mapKey)
135
- : await options.cache.getBlob(mapKey);
136
- await writeFiles((0, utils_1.blobToStream)(mapEntry), info, hashRefToNameHash, options, config, outputFS, (0, projectPath_1.toProjectPathUnsafe)((0, projectPath_1.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
141
+ let mapStream;
142
+ if ((0, feature_flags_1.getFeatureFlag)('fixSourceMapHashRefs') &&
143
+ bundleReplacements &&
144
+ bundleReplacements.length > 0) {
145
+ const mapEntry = (0, feature_flags_1.getFeatureFlag)('cachePerformanceImprovements')
146
+ ? await options.cache.getLargeBlob(mapKey)
147
+ : await options.cache.getBlob(mapKey);
148
+ const mapBuffer = Buffer.isBuffer(mapEntry)
149
+ ? mapEntry
150
+ : Buffer.from(mapEntry);
151
+ const projectRoot = typeof options.projectRoot === 'string'
152
+ ? options.projectRoot
153
+ : String(options.projectRoot);
154
+ const sourceMap = new source_map_1.default(projectRoot, mapBuffer);
155
+ applyReplacementsToSourceMap(sourceMap, bundleReplacements);
156
+ const mapJson = await sourceMap.stringify({
157
+ format: 'string',
158
+ file: name,
159
+ sourceRoot: computeSourceMapRoot(bundle, options),
160
+ });
161
+ mapStream = (0, utils_1.blobToStream)(Buffer.from(typeof mapJson === 'string' ? mapJson : JSON.stringify(mapJson), 'utf8'));
162
+ }
163
+ else {
164
+ const mapEntry = (0, feature_flags_1.getFeatureFlag)('cachePerformanceImprovements')
165
+ ? await options.cache.getLargeBlob(mapKey)
166
+ : await options.cache.getBlob(mapKey);
167
+ mapStream = (0, utils_1.blobToStream)(mapEntry);
168
+ }
169
+ await writeFiles(mapStream, info, hashRefToNameHash, options, config, outputFS, (0, projectPath_1.toProjectPathUnsafe)((0, projectPath_1.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
137
170
  }
138
171
  let res = {
139
172
  filePath,
@@ -147,13 +180,75 @@ async function run({ input, options, api }) {
147
180
  api.storeResult(res);
148
181
  return res;
149
182
  }
183
+ function applyReplacementsToSourceMap(sourceMap, replacements) {
184
+ if (replacements.length === 0)
185
+ return;
186
+ const sorted = [...replacements].sort((a, b) => a.line - b.line || a.column - b.column);
187
+ for (const r of sorted) {
188
+ const delta = r.newLength - r.originalLength;
189
+ if (delta !== 0) {
190
+ // r.column is in post-replacement coordinates (matching the already-shifted
191
+ // source map state after previous offsetColumns calls). The end of the
192
+ // placeholder in these coordinates is simply r.column + r.originalLength.
193
+ const offsetStartColumn = r.column + r.originalLength;
194
+ const line1Based = r.line + 1;
195
+ if (line1Based >= 1 && offsetStartColumn + delta >= 0) {
196
+ sourceMap.offsetColumns(line1Based, offsetStartColumn, delta);
197
+ }
198
+ }
199
+ }
200
+ }
201
+ /**
202
+ * Computes the sourceRoot for a source map file. This is the relative path from
203
+ * the output directory back to the project root, so that source paths (stored
204
+ * relative to projectRoot) resolve correctly from the .map file location.
205
+ *
206
+ * Returns undefined when sources are inlined (inlineSources), since the browser
207
+ * doesn't need to fetch them and sourceRoot would be unnecessary.
208
+ *
209
+ * This logic must stay in sync with PackagerRunner.generateSourceMap.
210
+ */
211
+ function computeSourceMapRoot(bundle, options) {
212
+ let name = (0, nullthrows_1.default)(bundle.name);
213
+ let filePath = (0, projectPath_1.joinProjectPath)(bundle.target.distDir, name);
214
+ let fullPath = (0, projectPath_1.fromProjectPath)(options.projectRoot, filePath);
215
+ let sourceRoot = path_1.default.relative(path_1.default.dirname(fullPath), options.projectRoot);
216
+ let inlineSources = false;
217
+ const bundleEnv = (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env);
218
+ if (bundle.target) {
219
+ const bundleTargetEnv = (0, EnvironmentManager_1.fromEnvironmentId)(bundle.target.env);
220
+ if (bundleEnv.sourceMap && bundleEnv.sourceMap.sourceRoot !== undefined) {
221
+ sourceRoot = bundleEnv.sourceMap.sourceRoot;
222
+ }
223
+ else if (options.serveOptions && bundleTargetEnv.context === 'browser') {
224
+ sourceRoot = '/__parcel_source_root';
225
+ }
226
+ if (bundleEnv.sourceMap &&
227
+ bundleEnv.sourceMap.inlineSources !== undefined) {
228
+ inlineSources = bundleEnv.sourceMap.inlineSources;
229
+ }
230
+ else if (bundleTargetEnv.context !== 'node') {
231
+ inlineSources = options.mode === 'production';
232
+ }
233
+ }
234
+ let isInlineMap = bundleEnv.sourceMap && bundleEnv.sourceMap.inline;
235
+ if ((0, feature_flags_1.getFeatureFlag)('omitSourcesContentInMemory') && !isInlineMap) {
236
+ if (!(bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources === false)) {
237
+ inlineSources = true;
238
+ }
239
+ }
240
+ if (inlineSources) {
241
+ return undefined;
242
+ }
243
+ return url_1.default.format(url_1.default.parse(sourceRoot + '/'));
244
+ }
150
245
  async function writeFiles(
151
246
  // @ts-expect-error TS2503
152
- inputStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api) {
247
+ inputStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api, bundleReplacements) {
153
248
  let compressors = await config.getCompressors((0, projectPath_1.fromProjectPathRelative)(filePath));
154
249
  let fullPath = (0, projectPath_1.fromProjectPath)(options.projectRoot, filePath);
155
250
  let stream = info.hashReferences.length
156
- ? inputStream.pipe(replaceStream(hashRefToNameHash))
251
+ ? inputStream.pipe(replaceStream(hashRefToNameHash, bundleReplacements))
157
252
  : inputStream;
158
253
  let promises = [];
159
254
  for (let compressor of compressors) {
@@ -202,9 +297,23 @@ stream, options, outputFS, filePath, writeOptions, devDeps, api) {
202
297
  await (0, DevDepRequest_1.runDevDepRequest)(api, devDepRequest);
203
298
  }
204
299
  }
205
- function replaceStream(hashRefToNameHash) {
300
+ function advanceLineColumn(line, column, buf) {
301
+ for (let i = 0; i < buf.length; i++) {
302
+ if (buf[i] === 0x0a) {
303
+ line++;
304
+ column = 0;
305
+ }
306
+ else {
307
+ column++;
308
+ }
309
+ }
310
+ return { line, column };
311
+ }
312
+ function replaceStream(hashRefToNameHash, replacements) {
206
313
  let boundaryStr = Buffer.alloc(0);
207
314
  let replaced = Buffer.alloc(0);
315
+ let outputLine = 0;
316
+ let outputColumn = 0;
208
317
  return new stream_1.Transform({
209
318
  transform(chunk, encoding, cb) {
210
319
  let str = Buffer.concat([boundaryStr, Buffer.from(chunk)]);
@@ -225,15 +334,29 @@ function replaceStream(hashRefToNameHash) {
225
334
  .subarray(matchI, matchI + HASH_REF_PREFIX_LEN + constants_1.HASH_REF_HASH_LEN)
226
335
  .toString();
227
336
  let replacement = Buffer.from(hashRefToNameHash.get(match) ?? match);
337
+ // Copy pre-match content FIRST so position calculation includes it
228
338
  replaced.set(str.subarray(lastMatchI, matchI), replacedLength);
229
339
  replacedLength += matchI - lastMatchI;
340
+ if (replacements) {
341
+ const pos = advanceLineColumn(outputLine, outputColumn, replaced.subarray(0, replacedLength));
342
+ replacements.push({
343
+ line: pos.line,
344
+ column: pos.column,
345
+ originalLength: HASH_REF_PLACEHOLDER_LEN,
346
+ newLength: replacement.byteLength,
347
+ });
348
+ }
230
349
  replaced.set(replacement, replacedLength);
231
350
  replacedLength += replacement.byteLength;
232
351
  lastMatchI = matchI + HASH_REF_PREFIX_LEN + constants_1.HASH_REF_HASH_LEN;
233
352
  }
234
353
  }
354
+ const pushLen = replacedLength - BOUNDARY_LENGTH;
355
+ const pushed = advanceLineColumn(outputLine, outputColumn, replaced.subarray(0, pushLen));
356
+ outputLine = pushed.line;
357
+ outputColumn = pushed.column;
235
358
  boundaryStr = replaced.subarray(replacedLength - BOUNDARY_LENGTH, replacedLength);
236
- let strUpToBoundary = replaced.subarray(0, replacedLength - BOUNDARY_LENGTH);
359
+ let strUpToBoundary = replaced.subarray(0, pushLen);
237
360
  cb(null, strUpToBoundary);
238
361
  },
239
362
  flush(cb) {
@@ -15,6 +15,14 @@ const rust_1 = require("@atlaspack/rust");
15
15
  const PackageRequest_1 = require("./PackageRequest");
16
16
  const WriteBundleRequest_1 = __importDefault(require("./WriteBundleRequest"));
17
17
  const utils_1 = require("@atlaspack/utils");
18
+ /** Length of the hash suffix in output filenames (e.g. .runtime.13dc01ac.js). */
19
+ const NAME_HASH_DISPLAY_LEN = 8;
20
+ /** Use at most NAME_HASH_DISPLAY_LEN chars for the name hash so filenames stay short. */
21
+ function nameHashForFilename(hash) {
22
+ return hash.length <= NAME_HASH_DISPLAY_LEN
23
+ ? hash
24
+ : hash.slice(-NAME_HASH_DISPLAY_LEN);
25
+ }
18
26
  function reportPackagingProgress(completeBundles, totalBundles) {
19
27
  if (!(0, feature_flags_1.getFeatureFlag)('cliProgressReportingImprovements')) {
20
28
  return;
@@ -57,9 +65,9 @@ async function run({ input, api, farm, options, }) {
57
65
  // Do not package and write placeholder bundles to disk. We just
58
66
  // need to update the name so other bundles can reference it.
59
67
  if (bundle.isPlaceholder) {
60
- let hash = bundle.id.slice(-8);
61
- hashRefToNameHash.set(bundle.hashReference, hash);
62
- let name = (0, nullthrows_1.default)(bundle.name, `Expected ${bundle.type} bundle to have a name`).replace(bundle.hashReference, hash);
68
+ const nameHash = nameHashForFilename(bundle.id);
69
+ hashRefToNameHash.set(bundle.hashReference, nameHash);
70
+ let name = (0, nullthrows_1.default)(bundle.name, `Expected ${bundle.type} bundle to have a name`).replace(bundle.hashReference, nameHash);
63
71
  res.set(bundle.id, {
64
72
  filePath: (0, projectPath_1.joinProjectPath)(bundle.target.distDir, name),
65
73
  bundleId: bundle.id,
@@ -106,9 +114,7 @@ async function run({ input, api, farm, options, }) {
106
114
  }
107
115
  bundleInfoMap[bundle.id] = info;
108
116
  if (!info.hashReferences.length) {
109
- hashRefToNameHash.set(bundle.hashReference, options.shouldContentHash
110
- ? info.hash.slice(-8)
111
- : bundle.id.slice(-8));
117
+ hashRefToNameHash.set(bundle.hashReference, nameHashForFilename(options.shouldContentHash ? info.hash : bundle.id));
112
118
  let writeBundleRequest = (0, WriteBundleRequest_1.default)({
113
119
  bundle,
114
120
  info,
@@ -162,11 +168,11 @@ function assignComplexNameHashes(hashRefToNameHash, bundles, bundleInfoMap, opti
162
168
  if (hashRefToNameHash.get(bundle.hashReference) != null) {
163
169
  continue;
164
170
  }
165
- hashRefToNameHash.set(bundle.hashReference, options.shouldContentHash
171
+ hashRefToNameHash.set(bundle.hashReference, nameHashForFilename(options.shouldContentHash
166
172
  ? (0, rust_1.hashString)([...getBundlesIncludedInHash(bundle.id, bundleInfoMap)]
167
173
  .map((bundleId) => bundleInfoMap[bundleId].hash)
168
- .join(':')).slice(-8)
169
- : bundle.id.slice(-8));
174
+ .join(':'))
175
+ : bundle.id));
170
176
  }
171
177
  }
172
178
  function getBundlesIncludedInHash(bundleId, bundleInfoMap, included = new Set()) {
@@ -60,13 +60,6 @@ function _path() {
60
60
  };
61
61
  return data;
62
62
  }
63
- function _url() {
64
- const data = _interopRequireDefault(require("url"));
65
- _url = function () {
66
- return data;
67
- };
68
- return data;
69
- }
70
63
  function _rust() {
71
64
  const data = require("@atlaspack/rust");
72
65
  _rust = function () {
@@ -85,6 +78,7 @@ var _ConfigRequest = require("./requests/ConfigRequest");
85
78
  var _DevDepRequest = require("./requests/DevDepRequest");
86
79
  var _assetUtils = require("./assetUtils");
87
80
  var _utils2 = require("./utils");
81
+ var _WriteBundleRequest = require("./requests/WriteBundleRequest");
88
82
  function _profiler() {
89
83
  const data = require("@atlaspack/profiler");
90
84
  _profiler = function () {
@@ -407,42 +401,18 @@ class PackagerRunner {
407
401
  return optimized;
408
402
  }
409
403
  async generateSourceMap(bundle, map) {
410
- // sourceRoot should be a relative path between outDir and rootDir for node.js targets
404
+ let sourceRoot = (0, _WriteBundleRequest.computeSourceMapRoot)(bundle, this.options);
405
+ let inlineSources = sourceRoot === undefined;
411
406
  let filePath = (0, _projectPath.joinProjectPath)(bundle.target.distDir, (0, _nullthrows().default)(bundle.name));
412
407
  let fullPath = (0, _projectPath.fromProjectPath)(this.options.projectRoot, filePath);
413
- let sourceRoot = _path().default.relative(_path().default.dirname(fullPath), this.options.projectRoot);
414
- let inlineSources = false;
415
- const bundleEnv = (0, _EnvironmentManager.fromEnvironmentId)(bundle.env);
416
- if (bundle.target) {
417
- const bundleTargetEnv = (0, _EnvironmentManager.fromEnvironmentId)(bundle.target.env);
418
- if (bundleEnv.sourceMap && bundleEnv.sourceMap.sourceRoot !== undefined) {
419
- sourceRoot = bundleEnv.sourceMap.sourceRoot;
420
- } else if (this.options.serveOptions && bundleTargetEnv.context === 'browser') {
421
- sourceRoot = '/__parcel_source_root';
422
- }
423
- if (bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources !== undefined) {
424
- inlineSources = bundleEnv.sourceMap.inlineSources;
425
- } else if (bundleTargetEnv.context !== 'node') {
426
- // inlining should only happen in production for browser targets by default
427
- inlineSources = this.options.mode === 'production';
428
- }
429
- }
430
408
  let mapFilename = fullPath + '.map';
409
+ const bundleEnv = (0, _EnvironmentManager.fromEnvironmentId)(bundle.env);
431
410
  let isInlineMap = bundleEnv.sourceMap && bundleEnv.sourceMap.inline;
432
- if ((0, _featureFlags().getFeatureFlag)('omitSourcesContentInMemory') && !isInlineMap) {
433
- if (!(bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources === false)) {
434
- /*
435
- We're omitting sourcesContent during transformation to allow GC to run.
436
- Ensure sources are still inlined into the final source maps written to disk. UNLESS the user explicitly disabled inlineSources.
437
- */
438
- inlineSources = true;
439
- }
440
- }
441
411
  let stringified = await map.stringify({
442
412
  file: _path().default.basename(mapFilename),
443
413
  fs: this.options.inputFS,
444
414
  rootDir: this.options.projectRoot,
445
- sourceRoot: !inlineSources ? _url().default.format(_url().default.parse(sourceRoot + '/')) : undefined,
415
+ sourceRoot,
446
416
  inlineSources,
447
417
  format: isInlineMap ? 'inline' : 'string'
448
418
  });
@@ -3,6 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.applyReplacementsToSourceMap = applyReplacementsToSourceMap;
7
+ exports.computeSourceMapRoot = computeSourceMapRoot;
6
8
  exports.default = createWriteBundleRequest;
7
9
  var _constants = require("../constants");
8
10
  function _nullthrows() {
@@ -19,6 +21,13 @@ function _path() {
19
21
  };
20
22
  return data;
21
23
  }
24
+ function _url() {
25
+ const data = _interopRequireDefault(require("url"));
26
+ _url = function () {
27
+ return data;
28
+ };
29
+ return data;
30
+ }
22
31
  var _Bundle = require("../public/Bundle");
23
32
  function _utils() {
24
33
  const data = require("@atlaspack/utils");
@@ -68,11 +77,19 @@ function _featureFlags() {
68
77
  return data;
69
78
  }
70
79
  var _EnvironmentManager = require("../EnvironmentManager");
80
+ function _sourceMap() {
81
+ const data = _interopRequireDefault(require("@atlaspack/source-map"));
82
+ _sourceMap = function () {
83
+ return data;
84
+ };
85
+ return data;
86
+ }
71
87
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
72
88
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
73
89
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
74
90
  const HASH_REF_PREFIX_LEN = _constants.HASH_REF_PREFIX.length;
75
91
  const BOUNDARY_LENGTH = _constants.HASH_REF_PREFIX.length + 32 - 1;
92
+ const HASH_REF_PLACEHOLDER_LEN = HASH_REF_PREFIX_LEN + _constants.HASH_REF_HASH_LEN;
76
93
  /**
77
94
  * Writes a bundle to the dist directory, replacing hash references with the final content hashes.
78
95
  */
@@ -158,11 +175,28 @@ async function run({
158
175
  invalidDevDeps
159
176
  } = await (0, _DevDepRequest.getDevDepRequests)(api);
160
177
  (0, _DevDepRequest.invalidateDevDeps)(invalidDevDeps, options, config);
161
- await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api);
178
+ const bundleReplacements = (0, _featureFlags().getFeatureFlag)('fixSourceMapHashRefs') ? [] : undefined;
179
+ await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api, bundleReplacements);
162
180
  const hasSourceMap = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.hasLargeBlob(mapKey) : await options.cache.has(mapKey);
163
181
  if (mapKey && env.sourceMap && !env.sourceMap.inline && hasSourceMap) {
164
- const mapEntry = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.getLargeBlob(mapKey) : await options.cache.getBlob(mapKey);
165
- await writeFiles((0, _utils().blobToStream)(mapEntry), info, hashRefToNameHash, options, config, outputFS, (0, _projectPath.toProjectPathUnsafe)((0, _projectPath.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
182
+ let mapStream;
183
+ if ((0, _featureFlags().getFeatureFlag)('fixSourceMapHashRefs') && bundleReplacements && bundleReplacements.length > 0) {
184
+ const mapEntry = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.getLargeBlob(mapKey) : await options.cache.getBlob(mapKey);
185
+ const mapBuffer = Buffer.isBuffer(mapEntry) ? mapEntry : Buffer.from(mapEntry);
186
+ const projectRoot = typeof options.projectRoot === 'string' ? options.projectRoot : String(options.projectRoot);
187
+ const sourceMap = new (_sourceMap().default)(projectRoot, mapBuffer);
188
+ applyReplacementsToSourceMap(sourceMap, bundleReplacements);
189
+ const mapJson = await sourceMap.stringify({
190
+ format: 'string',
191
+ file: name,
192
+ sourceRoot: computeSourceMapRoot(bundle, options)
193
+ });
194
+ mapStream = (0, _utils().blobToStream)(Buffer.from(typeof mapJson === 'string' ? mapJson : JSON.stringify(mapJson), 'utf8'));
195
+ } else {
196
+ const mapEntry = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.getLargeBlob(mapKey) : await options.cache.getBlob(mapKey);
197
+ mapStream = (0, _utils().blobToStream)(mapEntry);
198
+ }
199
+ await writeFiles(mapStream, info, hashRefToNameHash, options, config, outputFS, (0, _projectPath.toProjectPathUnsafe)((0, _projectPath.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
166
200
  }
167
201
  let res = {
168
202
  filePath,
@@ -176,12 +210,71 @@ async function run({
176
210
  api.storeResult(res);
177
211
  return res;
178
212
  }
213
+ function applyReplacementsToSourceMap(sourceMap, replacements) {
214
+ if (replacements.length === 0) return;
215
+ const sorted = [...replacements].sort((a, b) => a.line - b.line || a.column - b.column);
216
+ for (const r of sorted) {
217
+ const delta = r.newLength - r.originalLength;
218
+ if (delta !== 0) {
219
+ // r.column is in post-replacement coordinates (matching the already-shifted
220
+ // source map state after previous offsetColumns calls). The end of the
221
+ // placeholder in these coordinates is simply r.column + r.originalLength.
222
+ const offsetStartColumn = r.column + r.originalLength;
223
+ const line1Based = r.line + 1;
224
+ if (line1Based >= 1 && offsetStartColumn + delta >= 0) {
225
+ sourceMap.offsetColumns(line1Based, offsetStartColumn, delta);
226
+ }
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Computes the sourceRoot for a source map file. This is the relative path from
233
+ * the output directory back to the project root, so that source paths (stored
234
+ * relative to projectRoot) resolve correctly from the .map file location.
235
+ *
236
+ * Returns undefined when sources are inlined (inlineSources), since the browser
237
+ * doesn't need to fetch them and sourceRoot would be unnecessary.
238
+ *
239
+ * This logic must stay in sync with PackagerRunner.generateSourceMap.
240
+ */
241
+ function computeSourceMapRoot(bundle, options) {
242
+ let name = (0, _nullthrows().default)(bundle.name);
243
+ let filePath = (0, _projectPath.joinProjectPath)(bundle.target.distDir, name);
244
+ let fullPath = (0, _projectPath.fromProjectPath)(options.projectRoot, filePath);
245
+ let sourceRoot = _path().default.relative(_path().default.dirname(fullPath), options.projectRoot);
246
+ let inlineSources = false;
247
+ const bundleEnv = (0, _EnvironmentManager.fromEnvironmentId)(bundle.env);
248
+ if (bundle.target) {
249
+ const bundleTargetEnv = (0, _EnvironmentManager.fromEnvironmentId)(bundle.target.env);
250
+ if (bundleEnv.sourceMap && bundleEnv.sourceMap.sourceRoot !== undefined) {
251
+ sourceRoot = bundleEnv.sourceMap.sourceRoot;
252
+ } else if (options.serveOptions && bundleTargetEnv.context === 'browser') {
253
+ sourceRoot = '/__parcel_source_root';
254
+ }
255
+ if (bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources !== undefined) {
256
+ inlineSources = bundleEnv.sourceMap.inlineSources;
257
+ } else if (bundleTargetEnv.context !== 'node') {
258
+ inlineSources = options.mode === 'production';
259
+ }
260
+ }
261
+ let isInlineMap = bundleEnv.sourceMap && bundleEnv.sourceMap.inline;
262
+ if ((0, _featureFlags().getFeatureFlag)('omitSourcesContentInMemory') && !isInlineMap) {
263
+ if (!(bundleEnv.sourceMap && bundleEnv.sourceMap.inlineSources === false)) {
264
+ inlineSources = true;
265
+ }
266
+ }
267
+ if (inlineSources) {
268
+ return undefined;
269
+ }
270
+ return _url().default.format(_url().default.parse(sourceRoot + '/'));
271
+ }
179
272
  async function writeFiles(
180
273
  // @ts-expect-error TS2503
181
- inputStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api) {
274
+ inputStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api, bundleReplacements) {
182
275
  let compressors = await config.getCompressors((0, _projectPath.fromProjectPathRelative)(filePath));
183
276
  let fullPath = (0, _projectPath.fromProjectPath)(options.projectRoot, filePath);
184
- let stream = info.hashReferences.length ? inputStream.pipe(replaceStream(hashRefToNameHash)) : inputStream;
277
+ let stream = info.hashReferences.length ? inputStream.pipe(replaceStream(hashRefToNameHash, bundleReplacements)) : inputStream;
185
278
  let promises = [];
186
279
  for (let compressor of compressors) {
187
280
  promises.push(
@@ -230,9 +323,25 @@ stream, options, outputFS, filePath, writeOptions, devDeps, api) {
230
323
  await (0, _DevDepRequest.runDevDepRequest)(api, devDepRequest);
231
324
  }
232
325
  }
233
- function replaceStream(hashRefToNameHash) {
326
+ function advanceLineColumn(line, column, buf) {
327
+ for (let i = 0; i < buf.length; i++) {
328
+ if (buf[i] === 0x0a) {
329
+ line++;
330
+ column = 0;
331
+ } else {
332
+ column++;
333
+ }
334
+ }
335
+ return {
336
+ line,
337
+ column
338
+ };
339
+ }
340
+ function replaceStream(hashRefToNameHash, replacements) {
234
341
  let boundaryStr = Buffer.alloc(0);
235
342
  let replaced = Buffer.alloc(0);
343
+ let outputLine = 0;
344
+ let outputColumn = 0;
236
345
  return new (_stream().Transform)({
237
346
  transform(chunk, encoding, cb) {
238
347
  let str = Buffer.concat([boundaryStr, Buffer.from(chunk)]);
@@ -250,15 +359,29 @@ function replaceStream(hashRefToNameHash) {
250
359
  } else {
251
360
  let match = str.subarray(matchI, matchI + HASH_REF_PREFIX_LEN + _constants.HASH_REF_HASH_LEN).toString();
252
361
  let replacement = Buffer.from(hashRefToNameHash.get(match) ?? match);
362
+ // Copy pre-match content FIRST so position calculation includes it
253
363
  replaced.set(str.subarray(lastMatchI, matchI), replacedLength);
254
364
  replacedLength += matchI - lastMatchI;
365
+ if (replacements) {
366
+ const pos = advanceLineColumn(outputLine, outputColumn, replaced.subarray(0, replacedLength));
367
+ replacements.push({
368
+ line: pos.line,
369
+ column: pos.column,
370
+ originalLength: HASH_REF_PLACEHOLDER_LEN,
371
+ newLength: replacement.byteLength
372
+ });
373
+ }
255
374
  replaced.set(replacement, replacedLength);
256
375
  replacedLength += replacement.byteLength;
257
376
  lastMatchI = matchI + HASH_REF_PREFIX_LEN + _constants.HASH_REF_HASH_LEN;
258
377
  }
259
378
  }
379
+ const pushLen = replacedLength - BOUNDARY_LENGTH;
380
+ const pushed = advanceLineColumn(outputLine, outputColumn, replaced.subarray(0, pushLen));
381
+ outputLine = pushed.line;
382
+ outputColumn = pushed.column;
260
383
  boundaryStr = replaced.subarray(replacedLength - BOUNDARY_LENGTH, replacedLength);
261
- let strUpToBoundary = replaced.subarray(0, replacedLength - BOUNDARY_LENGTH);
384
+ let strUpToBoundary = replaced.subarray(0, pushLen);
262
385
  cb(null, strUpToBoundary);
263
386
  },
264
387
  flush(cb) {
@@ -40,6 +40,13 @@ function _utils() {
40
40
  return data;
41
41
  }
42
42
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
43
+ /** Length of the hash suffix in output filenames (e.g. .runtime.13dc01ac.js). */
44
+ const NAME_HASH_DISPLAY_LEN = 8;
45
+
46
+ /** Use at most NAME_HASH_DISPLAY_LEN chars for the name hash so filenames stay short. */
47
+ function nameHashForFilename(hash) {
48
+ return hash.length <= NAME_HASH_DISPLAY_LEN ? hash : hash.slice(-NAME_HASH_DISPLAY_LEN);
49
+ }
43
50
  function reportPackagingProgress(completeBundles, totalBundles) {
44
51
  if (!(0, _featureFlags().getFeatureFlag)('cliProgressReportingImprovements')) {
45
52
  return;
@@ -92,9 +99,9 @@ async function run({
92
99
  // Do not package and write placeholder bundles to disk. We just
93
100
  // need to update the name so other bundles can reference it.
94
101
  if (bundle.isPlaceholder) {
95
- let hash = bundle.id.slice(-8);
96
- hashRefToNameHash.set(bundle.hashReference, hash);
97
- let name = (0, _nullthrows().default)(bundle.name, `Expected ${bundle.type} bundle to have a name`).replace(bundle.hashReference, hash);
102
+ const nameHash = nameHashForFilename(bundle.id);
103
+ hashRefToNameHash.set(bundle.hashReference, nameHash);
104
+ let name = (0, _nullthrows().default)(bundle.name, `Expected ${bundle.type} bundle to have a name`).replace(bundle.hashReference, nameHash);
98
105
  res.set(bundle.id, {
99
106
  filePath: (0, _projectPath.joinProjectPath)(bundle.target.distDir, name),
100
107
  bundleId: bundle.id,
@@ -143,7 +150,7 @@ async function run({
143
150
  }
144
151
  bundleInfoMap[bundle.id] = info;
145
152
  if (!info.hashReferences.length) {
146
- hashRefToNameHash.set(bundle.hashReference, options.shouldContentHash ? info.hash.slice(-8) : bundle.id.slice(-8));
153
+ hashRefToNameHash.set(bundle.hashReference, nameHashForFilename(options.shouldContentHash ? info.hash : bundle.id));
147
154
  let writeBundleRequest = (0, _WriteBundleRequest.default)({
148
155
  bundle,
149
156
  info,
@@ -195,7 +202,7 @@ function assignComplexNameHashes(hashRefToNameHash, bundles, bundleInfoMap, opti
195
202
  if (hashRefToNameHash.get(bundle.hashReference) != null) {
196
203
  continue;
197
204
  }
198
- hashRefToNameHash.set(bundle.hashReference, options.shouldContentHash ? (0, _rust().hashString)([...getBundlesIncludedInHash(bundle.id, bundleInfoMap)].map(bundleId => bundleInfoMap[bundleId].hash).join(':')).slice(-8) : bundle.id.slice(-8));
205
+ hashRefToNameHash.set(bundle.hashReference, nameHashForFilename(options.shouldContentHash ? (0, _rust().hashString)([...getBundlesIncludedInHash(bundle.id, bundleInfoMap)].map(bundleId => bundleInfoMap[bundleId].hash).join(':')) : bundle.id));
199
206
  }
200
207
  }
201
208
  function getBundlesIncludedInHash(bundleId, bundleInfoMap, included = new Set()) {