@atlaspack/runtime-js 2.12.1-canary.3589 → 2.12.1-canary.3592
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/lib/JSRuntime.js +17 -4
- package/lib/helpers/bundle-url.js +20 -8
- package/package.json +8 -7
- package/src/JSRuntime.js +25 -8
- package/src/helpers/bundle-url.js +19 -5
- package/test/bundle-url.test.js +62 -0
- package/lib/helpers/bundle-url-common.js +0 -13
- package/lib/helpers/bundle-url-shards.js +0 -86
- package/src/helpers/bundle-url-common.js +0 -14
- package/src/helpers/bundle-url-shards.js +0 -99
- package/test/bundle-url-common.test.js +0 -29
- package/test/bundle-url-shards.test.js +0 -132
package/lib/JSRuntime.js
CHANGED
|
@@ -404,7 +404,16 @@ function getLoaderRuntime({
|
|
|
404
404
|
} else if (to.type === 'js' && to.env.outputFormat === 'commonjs') {
|
|
405
405
|
return `Promise.resolve(__parcel__require__("./" + ${relativePathExpr}))`;
|
|
406
406
|
}
|
|
407
|
-
let absoluteUrlExpr
|
|
407
|
+
let absoluteUrlExpr;
|
|
408
|
+
if (shouldUseRuntimeManifest(bundle, options)) {
|
|
409
|
+
let publicId = JSON.stringify(to.publicId);
|
|
410
|
+
absoluteUrlExpr = `require('./helpers/bundle-manifest').resolve(${publicId})`;
|
|
411
|
+
if (shardingConfig) {
|
|
412
|
+
absoluteUrlExpr = `require('@atlaspack/domain-sharding').shardUrl(${absoluteUrlExpr}, ${shardingConfig.maxShards})`;
|
|
413
|
+
}
|
|
414
|
+
} else {
|
|
415
|
+
absoluteUrlExpr = getAbsoluteUrlExpr(relativePathExpr, bundle, to, shardingConfig);
|
|
416
|
+
}
|
|
408
417
|
let code = `require(${JSON.stringify(loader)})(${absoluteUrlExpr})`;
|
|
409
418
|
|
|
410
419
|
// In development, clear the require cache when an error occurs so the
|
|
@@ -546,6 +555,9 @@ function getURLRuntime(dependency, from, to, options, shardingConfig) {
|
|
|
546
555
|
} else {
|
|
547
556
|
code += `let bundleURL = require('./helpers/bundle-url');\n`;
|
|
548
557
|
code += `let url = bundleURL.getBundleURL('${from.publicId}') + ${relativePathExpr};`;
|
|
558
|
+
if (shardingConfig) {
|
|
559
|
+
code += `url = require('@atlaspack/domain-sharding').shardUrl(url, ${shardingConfig.maxShards});`;
|
|
560
|
+
}
|
|
549
561
|
code += `module.exports = workerURL(url, bundleURL.getOrigin(url), ${String(from.env.outputFormat === 'esmodule')});`;
|
|
550
562
|
}
|
|
551
563
|
} else {
|
|
@@ -602,10 +614,11 @@ function getAbsoluteUrlExpr(relativePathExpr, fromBundle, toBundle, shardingConf
|
|
|
602
614
|
// This will be compiled to new URL(url, import.meta.url) or new URL(url, 'file:' + __filename).
|
|
603
615
|
return `new __parcel__URL__(${relativePathExpr}).toString()`;
|
|
604
616
|
}
|
|
605
|
-
|
|
606
|
-
|
|
617
|
+
const regularBundleUrl = `require('./helpers/bundle-url').getBundleURL('${fromBundle.publicId}') + ${relativePathExpr}`;
|
|
618
|
+
if (!shardingConfig) {
|
|
619
|
+
return regularBundleUrl;
|
|
607
620
|
}
|
|
608
|
-
return `require('
|
|
621
|
+
return `require('@atlaspack/domain-sharding').shardUrl(${regularBundleUrl}, ${shardingConfig.maxShards})`;
|
|
609
622
|
}
|
|
610
623
|
function shouldUseRuntimeManifest(bundle, options) {
|
|
611
624
|
let env = bundle.env;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
getBaseURL = _require.getBaseURL,
|
|
5
|
-
stackTraceUrlRegexp = _require.stackTraceUrlRegexp;
|
|
3
|
+
var stackTraceUrlRegexp = /(https?|file|ftp|(chrome|moz|safari-web)-extension):\/\/[^)\n]+/g;
|
|
6
4
|
var bundleURL = {};
|
|
7
5
|
|
|
8
6
|
/**
|
|
@@ -10,19 +8,30 @@ var bundleURL = {};
|
|
|
10
8
|
* If the URL is not cached, it computes and stores it in the cache.
|
|
11
9
|
*
|
|
12
10
|
* @param {string} id - The identifier for the bundle.
|
|
11
|
+
* @param {Error?} inputError - An error object to extract the stack trace from
|
|
12
|
+
* (for testing purposes).
|
|
13
13
|
* @returns {string} The URL of the bundle, without file name.
|
|
14
14
|
*/
|
|
15
|
-
function getBundleURLCached(id) {
|
|
15
|
+
function getBundleURLCached(id, inputError) {
|
|
16
16
|
var value = bundleURL[id];
|
|
17
17
|
if (!value) {
|
|
18
|
-
value = getBundleURL();
|
|
18
|
+
value = getBundleURL(inputError);
|
|
19
19
|
bundleURL[id] = value;
|
|
20
20
|
}
|
|
21
21
|
return value;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
/** Get the URL without the filename (last / segment)
|
|
25
|
+
*
|
|
26
|
+
* @param {string} url
|
|
27
|
+
* @returns {string} The URL with the file name removed
|
|
28
|
+
*/
|
|
29
|
+
function getBaseURL(url) {
|
|
30
|
+
return url.slice(0, url.lastIndexOf('/')) + '/';
|
|
31
|
+
}
|
|
32
|
+
function getBundleURL(inputError) {
|
|
24
33
|
try {
|
|
25
|
-
throw new Error();
|
|
34
|
+
throw inputError !== null && inputError !== void 0 ? inputError : new Error();
|
|
26
35
|
} catch (err) {
|
|
27
36
|
var matches = ('' + err.stack).match(stackTraceUrlRegexp);
|
|
28
37
|
if (matches) {
|
|
@@ -41,5 +50,8 @@ function getBundleURL() {
|
|
|
41
50
|
function getOrigin(url) {
|
|
42
51
|
return new URL(url).origin;
|
|
43
52
|
}
|
|
53
|
+
|
|
54
|
+
// TODO: convert this file to ESM once HMR issues are resolved
|
|
44
55
|
exports.getOrigin = getOrigin;
|
|
45
|
-
exports.getBundleURL = getBundleURLCached;
|
|
56
|
+
exports.getBundleURL = getBundleURLCached;
|
|
57
|
+
exports.getBaseURL = getBaseURL;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/runtime-js",
|
|
3
|
-
"version": "2.12.1-canary.
|
|
3
|
+
"version": "2.12.1-canary.3592+27d350650",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -12,15 +12,16 @@
|
|
|
12
12
|
"main": "lib/JSRuntime.js",
|
|
13
13
|
"source": "src/JSRuntime.js",
|
|
14
14
|
"engines": {
|
|
15
|
-
"atlaspack": "2.12.1-canary.
|
|
15
|
+
"atlaspack": "2.12.1-canary.3592+27d350650",
|
|
16
16
|
"node": ">= 16.0.0"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@atlaspack/diagnostic": "2.12.1-canary.
|
|
20
|
-
"@atlaspack/
|
|
21
|
-
"@atlaspack/
|
|
22
|
-
"@atlaspack/
|
|
19
|
+
"@atlaspack/diagnostic": "2.12.1-canary.3592+27d350650",
|
|
20
|
+
"@atlaspack/domain-sharding": "2.12.1-canary.3592+27d350650",
|
|
21
|
+
"@atlaspack/feature-flags": "2.12.1-canary.3592+27d350650",
|
|
22
|
+
"@atlaspack/plugin": "2.12.1-canary.3592+27d350650",
|
|
23
|
+
"@atlaspack/utils": "2.12.1-canary.3592+27d350650",
|
|
23
24
|
"nullthrows": "^1.1.1"
|
|
24
25
|
},
|
|
25
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "27d35065043dfc8669fe2618748cb3c6300c760a"
|
|
26
27
|
}
|
package/src/JSRuntime.js
CHANGED
|
@@ -485,11 +485,23 @@ function getLoaderRuntime({
|
|
|
485
485
|
return `Promise.resolve(__parcel__require__("./" + ${relativePathExpr}))`;
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
-
let absoluteUrlExpr
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
488
|
+
let absoluteUrlExpr;
|
|
489
|
+
if (shouldUseRuntimeManifest(bundle, options)) {
|
|
490
|
+
let publicId = JSON.stringify(to.publicId);
|
|
491
|
+
absoluteUrlExpr = `require('./helpers/bundle-manifest').resolve(${publicId})`;
|
|
492
|
+
|
|
493
|
+
if (shardingConfig) {
|
|
494
|
+
absoluteUrlExpr = `require('@atlaspack/domain-sharding').shardUrl(${absoluteUrlExpr}, ${shardingConfig.maxShards})`;
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
absoluteUrlExpr = getAbsoluteUrlExpr(
|
|
498
|
+
relativePathExpr,
|
|
499
|
+
bundle,
|
|
500
|
+
to,
|
|
501
|
+
shardingConfig,
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
493
505
|
let code = `require(${JSON.stringify(loader)})(${absoluteUrlExpr})`;
|
|
494
506
|
|
|
495
507
|
// In development, clear the require cache when an error occurs so the
|
|
@@ -732,6 +744,9 @@ function getURLRuntime(
|
|
|
732
744
|
} else {
|
|
733
745
|
code += `let bundleURL = require('./helpers/bundle-url');\n`;
|
|
734
746
|
code += `let url = bundleURL.getBundleURL('${from.publicId}') + ${relativePathExpr};`;
|
|
747
|
+
if (shardingConfig) {
|
|
748
|
+
code += `url = require('@atlaspack/domain-sharding').shardUrl(url, ${shardingConfig.maxShards});`;
|
|
749
|
+
}
|
|
735
750
|
code += `module.exports = workerURL(url, bundleURL.getOrigin(url), ${String(
|
|
736
751
|
from.env.outputFormat === 'esmodule',
|
|
737
752
|
)});`;
|
|
@@ -827,11 +842,13 @@ function getAbsoluteUrlExpr(
|
|
|
827
842
|
return `new __parcel__URL__(${relativePathExpr}).toString()`;
|
|
828
843
|
}
|
|
829
844
|
|
|
830
|
-
|
|
831
|
-
|
|
845
|
+
const regularBundleUrl = `require('./helpers/bundle-url').getBundleURL('${fromBundle.publicId}') + ${relativePathExpr}`;
|
|
846
|
+
|
|
847
|
+
if (!shardingConfig) {
|
|
848
|
+
return regularBundleUrl;
|
|
832
849
|
}
|
|
833
850
|
|
|
834
|
-
return `require('
|
|
851
|
+
return `require('@atlaspack/domain-sharding').shardUrl(${regularBundleUrl}, ${shardingConfig.maxShards})`;
|
|
835
852
|
}
|
|
836
853
|
|
|
837
854
|
function shouldUseRuntimeManifest(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const stackTraceUrlRegexp =
|
|
2
|
+
/(https?|file|ftp|(chrome|moz|safari-web)-extension):\/\/[^)\n]+/g;
|
|
2
3
|
|
|
3
4
|
const bundleURL = {};
|
|
4
5
|
|
|
@@ -7,22 +8,33 @@ const bundleURL = {};
|
|
|
7
8
|
* If the URL is not cached, it computes and stores it in the cache.
|
|
8
9
|
*
|
|
9
10
|
* @param {string} id - The identifier for the bundle.
|
|
11
|
+
* @param {Error?} inputError - An error object to extract the stack trace from
|
|
12
|
+
* (for testing purposes).
|
|
10
13
|
* @returns {string} The URL of the bundle, without file name.
|
|
11
14
|
*/
|
|
12
|
-
function getBundleURLCached(id) {
|
|
15
|
+
function getBundleURLCached(id, inputError) {
|
|
13
16
|
let value = bundleURL[id];
|
|
14
17
|
|
|
15
18
|
if (!value) {
|
|
16
|
-
value = getBundleURL();
|
|
19
|
+
value = getBundleURL(inputError);
|
|
17
20
|
bundleURL[id] = value;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
return value;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
/** Get the URL without the filename (last / segment)
|
|
27
|
+
*
|
|
28
|
+
* @param {string} url
|
|
29
|
+
* @returns {string} The URL with the file name removed
|
|
30
|
+
*/
|
|
31
|
+
function getBaseURL(url) {
|
|
32
|
+
return url.slice(0, url.lastIndexOf('/')) + '/';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getBundleURL(inputError) {
|
|
24
36
|
try {
|
|
25
|
-
throw new Error();
|
|
37
|
+
throw inputError ?? new Error();
|
|
26
38
|
} catch (err) {
|
|
27
39
|
var matches = ('' + err.stack).match(stackTraceUrlRegexp);
|
|
28
40
|
if (matches) {
|
|
@@ -43,5 +55,7 @@ function getOrigin(url) {
|
|
|
43
55
|
return new URL(url).origin;
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
// TODO: convert this file to ESM once HMR issues are resolved
|
|
46
59
|
exports.getOrigin = getOrigin;
|
|
47
60
|
exports.getBundleURL = getBundleURLCached;
|
|
61
|
+
exports.getBaseURL = getBaseURL;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
|
|
4
|
+
import {getBaseURL, getBundleURL} from '../src/helpers/bundle-url';
|
|
5
|
+
|
|
6
|
+
const createErrorStack = (url) => {
|
|
7
|
+
// This error stack is copied from a local dev, with a bunch
|
|
8
|
+
// of lines trimmed off the end so it's not unnecessarily long
|
|
9
|
+
return `
|
|
10
|
+
Error
|
|
11
|
+
at Object.getBundleURL (http://localhost:8081/main-bundle.1a2fa8b7.js:15688:29)
|
|
12
|
+
at Object.getBundleURLCached (http://localhost:8081/main-bundle.1a2fa8b7.js:15688:29)
|
|
13
|
+
at a7u9v.6d3ceb6ac67fea50 (${url}:361466:46)
|
|
14
|
+
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
15
|
+
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
16
|
+
at 7H8wc.react-intl-next (http://localhost:8081/main-bundle.1a2fa8b7.js:279746:28)
|
|
17
|
+
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
18
|
+
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
19
|
+
at 1nL5S../manifest (http://localhost:8081/main-bundle.1a2fa8b7.js:279714:17)
|
|
20
|
+
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
21
|
+
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
22
|
+
`.trim();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('getBaseUrl', () => {
|
|
26
|
+
it('should return the URL with the filename removed', () => {
|
|
27
|
+
const testUrl =
|
|
28
|
+
'https://bundle-shard-3.assets.example.com/assets/testBundle.123abc.js';
|
|
29
|
+
|
|
30
|
+
assert.equal(
|
|
31
|
+
getBaseURL(testUrl),
|
|
32
|
+
'https://bundle-shard-3.assets.example.com/assets/',
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should handle domains with no .', () => {
|
|
37
|
+
const testUrl = 'http://localhost/assets/testBundle.123abc.js';
|
|
38
|
+
|
|
39
|
+
assert.equal(getBaseURL(testUrl), 'http://localhost/assets/');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should handle domains with ports', () => {
|
|
43
|
+
const testUrl = 'http://localhost:8081/assets/testBundle.123abc.js';
|
|
44
|
+
|
|
45
|
+
assert.equal(getBaseURL(testUrl), 'http://localhost:8081/assets/');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('getBundleURL', () => {
|
|
50
|
+
it('should return the URL of the bundle without the file name', () => {
|
|
51
|
+
const testUrl =
|
|
52
|
+
'https://bundle-domain.assets.example.com/assets/testBundle.123abc.js';
|
|
53
|
+
|
|
54
|
+
const errorStack = createErrorStack(testUrl);
|
|
55
|
+
const error = new Error();
|
|
56
|
+
error.stack = errorStack;
|
|
57
|
+
|
|
58
|
+
const result = getBundleURL('test-asset', error);
|
|
59
|
+
|
|
60
|
+
assert.equal(result, 'https://bundle-domain.assets.example.com/assets/');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/** Get the URL without the filename (last / segment)
|
|
4
|
-
*
|
|
5
|
-
* @param {string} url
|
|
6
|
-
* @returns {string} The URL with the file name removed
|
|
7
|
-
*/
|
|
8
|
-
function getBaseURL(url) {
|
|
9
|
-
return url.slice(0, url.lastIndexOf('/')) + '/';
|
|
10
|
-
}
|
|
11
|
-
var stackTraceUrlRegexp = /(https?|file|ftp|(chrome|moz|safari-web)-extension):\/\/[^)\n]+/g;
|
|
12
|
-
exports.getBaseURL = getBaseURL;
|
|
13
|
-
exports.stackTraceUrlRegexp = stackTraceUrlRegexp;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _require = require('./bundle-url-common'),
|
|
4
|
-
getBaseURL = _require.getBaseURL,
|
|
5
|
-
stackTraceUrlRegexp = _require.stackTraceUrlRegexp;
|
|
6
|
-
var bundleURL = {};
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Retrieves the sharded bundle URL based on the bundle name and the maximum number of shards.
|
|
10
|
-
*
|
|
11
|
-
* @param {string} bundleName - The file name of the requested bundle.
|
|
12
|
-
* @param {number} maxShards - The maximum number of domain shards available.
|
|
13
|
-
* @param {Error} inputError - An error object to extract the stack trace from
|
|
14
|
-
* (for testing purposes).
|
|
15
|
-
* @returns {string} The URL of the sharded bundle, without file name.
|
|
16
|
-
*/
|
|
17
|
-
function getShardedBundleURL(bundleName, maxShards, inputError) {
|
|
18
|
-
var value = bundleURL[bundleName];
|
|
19
|
-
if (value) {
|
|
20
|
-
return value;
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
throw inputError !== null && inputError !== void 0 ? inputError : new Error();
|
|
24
|
-
} catch (err) {
|
|
25
|
-
var matches = ('' + err.stack).match(stackTraceUrlRegexp);
|
|
26
|
-
if (!matches) {
|
|
27
|
-
return '/';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// The first stack frame will be this function.
|
|
31
|
-
// Use the 2nd one, which will be a runtime in the original bundle.
|
|
32
|
-
var stackUrl = matches[1];
|
|
33
|
-
var baseUrl = getBaseURL(stackUrl);
|
|
34
|
-
|
|
35
|
-
// Global variable is set by SSR servers when HTTP1.1 traffic is detected
|
|
36
|
-
if (!globalThis.__ATLASPACK_ENABLE_DOMAIN_SHARDS) {
|
|
37
|
-
bundleURL[bundleName] = baseUrl;
|
|
38
|
-
return baseUrl;
|
|
39
|
-
}
|
|
40
|
-
var shardNumber = getDomainShardIndex(bundleName, maxShards);
|
|
41
|
-
var url = new URL(baseUrl);
|
|
42
|
-
var shardedDomain = getShardedDomain(url.hostname, shardNumber);
|
|
43
|
-
url.hostname = shardedDomain;
|
|
44
|
-
value = url.toString();
|
|
45
|
-
bundleURL[bundleName] = value;
|
|
46
|
-
return value;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function getDomainShardIndex(str, maxShards) {
|
|
50
|
-
var shard = str.split('').reduce(function (a, b) {
|
|
51
|
-
var n = (a << maxShards) - a + b.charCodeAt(0);
|
|
52
|
-
|
|
53
|
-
// The value returned by << is 64 bit, the & operator coerces to 32,
|
|
54
|
-
// prevents overflow as we iterate.
|
|
55
|
-
return n & n;
|
|
56
|
-
}, 0);
|
|
57
|
-
shard = shard % maxShards;
|
|
58
|
-
|
|
59
|
-
// Make number positive
|
|
60
|
-
if (shard < 0) {
|
|
61
|
-
shard += maxShards;
|
|
62
|
-
}
|
|
63
|
-
return shard;
|
|
64
|
-
}
|
|
65
|
-
function getShardedDomain(domain, shard) {
|
|
66
|
-
var i = domain.indexOf('.');
|
|
67
|
-
|
|
68
|
-
// Domains like localhost have no . separators
|
|
69
|
-
if (i === -1) {
|
|
70
|
-
return "".concat(removeTrailingShard(domain), "-").concat(shard);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// If this domain already has a shard number in it, strip it out before adding
|
|
74
|
-
// the new one
|
|
75
|
-
var firstSubdomain = removeTrailingShard(domain.slice(0, i));
|
|
76
|
-
return "".concat(firstSubdomain, "-").concat(shard).concat(domain.slice(i));
|
|
77
|
-
}
|
|
78
|
-
var trailingShardRegex = /-\d+$/;
|
|
79
|
-
function removeTrailingShard(subdomain) {
|
|
80
|
-
if (!trailingShardRegex.test(subdomain)) {
|
|
81
|
-
return subdomain;
|
|
82
|
-
}
|
|
83
|
-
var shardIdx = subdomain.lastIndexOf('-');
|
|
84
|
-
return subdomain.slice(0, shardIdx);
|
|
85
|
-
}
|
|
86
|
-
exports.getShardedBundleURL = getShardedBundleURL;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/** Get the URL without the filename (last / segment)
|
|
2
|
-
*
|
|
3
|
-
* @param {string} url
|
|
4
|
-
* @returns {string} The URL with the file name removed
|
|
5
|
-
*/
|
|
6
|
-
function getBaseURL(url) {
|
|
7
|
-
return url.slice(0, url.lastIndexOf('/')) + '/';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const stackTraceUrlRegexp =
|
|
11
|
-
/(https?|file|ftp|(chrome|moz|safari-web)-extension):\/\/[^)\n]+/g;
|
|
12
|
-
|
|
13
|
-
exports.getBaseURL = getBaseURL;
|
|
14
|
-
exports.stackTraceUrlRegexp = stackTraceUrlRegexp;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const {getBaseURL, stackTraceUrlRegexp} = require('./bundle-url-common');
|
|
2
|
-
|
|
3
|
-
const bundleURL = {};
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Retrieves the sharded bundle URL based on the bundle name and the maximum number of shards.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} bundleName - The file name of the requested bundle.
|
|
9
|
-
* @param {number} maxShards - The maximum number of domain shards available.
|
|
10
|
-
* @param {Error} inputError - An error object to extract the stack trace from
|
|
11
|
-
* (for testing purposes).
|
|
12
|
-
* @returns {string} The URL of the sharded bundle, without file name.
|
|
13
|
-
*/
|
|
14
|
-
function getShardedBundleURL(bundleName, maxShards, inputError) {
|
|
15
|
-
let value = bundleURL[bundleName];
|
|
16
|
-
|
|
17
|
-
if (value) {
|
|
18
|
-
return value;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
throw inputError ?? new Error();
|
|
23
|
-
} catch (err) {
|
|
24
|
-
var matches = ('' + err.stack).match(stackTraceUrlRegexp);
|
|
25
|
-
|
|
26
|
-
if (!matches) {
|
|
27
|
-
return '/';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// The first stack frame will be this function.
|
|
31
|
-
// Use the 2nd one, which will be a runtime in the original bundle.
|
|
32
|
-
const stackUrl = matches[1];
|
|
33
|
-
const baseUrl = getBaseURL(stackUrl);
|
|
34
|
-
|
|
35
|
-
// Global variable is set by SSR servers when HTTP1.1 traffic is detected
|
|
36
|
-
if (!globalThis.__ATLASPACK_ENABLE_DOMAIN_SHARDS) {
|
|
37
|
-
bundleURL[bundleName] = baseUrl;
|
|
38
|
-
return baseUrl;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const shardNumber = getDomainShardIndex(bundleName, maxShards);
|
|
42
|
-
const url = new URL(baseUrl);
|
|
43
|
-
|
|
44
|
-
const shardedDomain = getShardedDomain(url.hostname, shardNumber);
|
|
45
|
-
url.hostname = shardedDomain;
|
|
46
|
-
|
|
47
|
-
value = url.toString();
|
|
48
|
-
|
|
49
|
-
bundleURL[bundleName] = value;
|
|
50
|
-
return value;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getDomainShardIndex(str, maxShards) {
|
|
55
|
-
let shard = str.split('').reduce((a, b) => {
|
|
56
|
-
const n = (a << maxShards) - a + b.charCodeAt(0);
|
|
57
|
-
|
|
58
|
-
// The value returned by << is 64 bit, the & operator coerces to 32,
|
|
59
|
-
// prevents overflow as we iterate.
|
|
60
|
-
return n & n;
|
|
61
|
-
}, 0);
|
|
62
|
-
|
|
63
|
-
shard = shard % maxShards;
|
|
64
|
-
|
|
65
|
-
// Make number positive
|
|
66
|
-
if (shard < 0) {
|
|
67
|
-
shard += maxShards;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return shard;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function getShardedDomain(domain, shard) {
|
|
74
|
-
let i = domain.indexOf('.');
|
|
75
|
-
|
|
76
|
-
// Domains like localhost have no . separators
|
|
77
|
-
if (i === -1) {
|
|
78
|
-
return `${removeTrailingShard(domain)}-${shard}`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// If this domain already has a shard number in it, strip it out before adding
|
|
82
|
-
// the new one
|
|
83
|
-
const firstSubdomain = removeTrailingShard(domain.slice(0, i));
|
|
84
|
-
|
|
85
|
-
return `${firstSubdomain}-${shard}${domain.slice(i)}`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const trailingShardRegex = /-\d+$/;
|
|
89
|
-
|
|
90
|
-
function removeTrailingShard(subdomain) {
|
|
91
|
-
if (!trailingShardRegex.test(subdomain)) {
|
|
92
|
-
return subdomain;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const shardIdx = subdomain.lastIndexOf('-');
|
|
96
|
-
return subdomain.slice(0, shardIdx);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
exports.getShardedBundleURL = getShardedBundleURL;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
|
|
4
|
-
// $FlowFixMe importing TypeScript
|
|
5
|
-
import {getBaseURL} from '../src/helpers/bundle-url-common';
|
|
6
|
-
|
|
7
|
-
describe('getBaseUrl', () => {
|
|
8
|
-
it('should return the URL with the filename removed', () => {
|
|
9
|
-
const testUrl =
|
|
10
|
-
'https://bundle-shard-3.assets.example.com/assets/testBundle.123abc.js';
|
|
11
|
-
|
|
12
|
-
assert.equal(
|
|
13
|
-
getBaseURL(testUrl),
|
|
14
|
-
'https://bundle-shard-3.assets.example.com/assets/',
|
|
15
|
-
);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should handle domains with no .', () => {
|
|
19
|
-
const testUrl = 'http://localhost/assets/testBundle.123abc.js';
|
|
20
|
-
|
|
21
|
-
assert.equal(getBaseURL(testUrl), 'http://localhost/assets/');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should handle domains with ports', () => {
|
|
25
|
-
const testUrl = 'http://localhost:8081/assets/testBundle.123abc.js';
|
|
26
|
-
|
|
27
|
-
assert.equal(getBaseURL(testUrl), 'http://localhost:8081/assets/');
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import assert from 'assert';
|
|
3
|
-
|
|
4
|
-
import {fsFixture, overlayFS, bundle} from '@atlaspack/test-utils';
|
|
5
|
-
|
|
6
|
-
// $FlowFixMe importing TypeScript
|
|
7
|
-
import {getShardedBundleURL} from '../src/helpers/bundle-url-shards';
|
|
8
|
-
|
|
9
|
-
const createErrorStack = (url) => {
|
|
10
|
-
// This error stack is copied from a local dev, with a bunch
|
|
11
|
-
// of lines trimmed off the end so it's not unnecessarily long
|
|
12
|
-
return `
|
|
13
|
-
Error
|
|
14
|
-
at Object.getShardedBundleURL (http://localhost:8081/main-bundle.1a2fa8b7.js:15688:29)
|
|
15
|
-
at a7u9v.6d3ceb6ac67fea50 (${url}.1a2fa8b7.js:361466:46)
|
|
16
|
-
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
17
|
-
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
18
|
-
at 7H8wc.react-intl-next (http://localhost:8081/main-bundle.1a2fa8b7.js:279746:28)
|
|
19
|
-
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
20
|
-
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
21
|
-
at 1nL5S../manifest (http://localhost:8081/main-bundle.1a2fa8b7.js:279714:17)
|
|
22
|
-
at newRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:71:24)
|
|
23
|
-
at localRequire (http://localhost:8081/main-bundle.1a2fa8b7.js:84:35)
|
|
24
|
-
`.trim();
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
describe('bundle-url-shards helper', () => {
|
|
28
|
-
describe('getShardedBundleURL', () => {
|
|
29
|
-
beforeEach(() => {
|
|
30
|
-
// $FlowFixMe
|
|
31
|
-
delete globalThis.__ATLASPACK_ENABLE_DOMAIN_SHARDS;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should shard a URL if the global variable is set', () => {
|
|
35
|
-
const testBundle = 'test-bundle.123abc.js';
|
|
36
|
-
|
|
37
|
-
// $FlowFixMe
|
|
38
|
-
globalThis.__ATLASPACK_ENABLE_DOMAIN_SHARDS = true;
|
|
39
|
-
|
|
40
|
-
const err = new Error();
|
|
41
|
-
err.stack = createErrorStack(
|
|
42
|
-
'https://bundle-shard.assets.example.com/assets/ParentBundle.cba321.js',
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const result = getShardedBundleURL(testBundle, 5, err);
|
|
46
|
-
|
|
47
|
-
assert.equal(result, 'https://bundle-shard-0.assets.example.com/assets/');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should re-shard a domain that has already been sharded', () => {
|
|
51
|
-
const testBundle = 'TestBundle.1a2b3c.js';
|
|
52
|
-
|
|
53
|
-
// $FlowFixMe
|
|
54
|
-
globalThis.__ATLASPACK_ENABLE_DOMAIN_SHARDS = true;
|
|
55
|
-
|
|
56
|
-
const err = new Error();
|
|
57
|
-
err.stack = createErrorStack(
|
|
58
|
-
'https://bundle-shard-1.assets.example.com/assets/ParentBundle.cba321.js',
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const result = getShardedBundleURL(testBundle, 5, err);
|
|
62
|
-
|
|
63
|
-
assert.equal(result, 'https://bundle-shard-4.assets.example.com/assets/');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should not add a shard if the cookie is not present', () => {
|
|
67
|
-
const testBundle = 'UnshardedBundle.9z8x7y.js';
|
|
68
|
-
|
|
69
|
-
const err = new Error();
|
|
70
|
-
err.stack = createErrorStack(
|
|
71
|
-
'https://bundle-unsharded.assets.example.com/assets/ParentBundle.cba321.js',
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const result = getShardedBundleURL(testBundle, 5, err);
|
|
75
|
-
|
|
76
|
-
assert.equal(
|
|
77
|
-
result,
|
|
78
|
-
'https://bundle-unsharded.assets.example.com/assets/',
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('compiled into JS Runtime', () => {
|
|
84
|
-
it('should insert all arguments into compiled output', async () => {
|
|
85
|
-
const maxShards = 8;
|
|
86
|
-
await fsFixture(overlayFS)`
|
|
87
|
-
package.json:
|
|
88
|
-
{
|
|
89
|
-
"name": "bundle-sharding-test",
|
|
90
|
-
"@atlaspack/runtime-js": {
|
|
91
|
-
"domainSharding": {
|
|
92
|
-
"maxShards": ${maxShards}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
src/index.js:
|
|
98
|
-
async function fn() {
|
|
99
|
-
const a = await import('./a.js');
|
|
100
|
-
const b = await import('./b.js');
|
|
101
|
-
console.log('a', a, b);
|
|
102
|
-
}
|
|
103
|
-
fn();
|
|
104
|
-
|
|
105
|
-
src/a.js:
|
|
106
|
-
export const a = async () => {
|
|
107
|
-
const b = await import('./b');
|
|
108
|
-
return b + 'A';
|
|
109
|
-
}
|
|
110
|
-
src/b.js:
|
|
111
|
-
export const b = 'B';
|
|
112
|
-
|
|
113
|
-
yarn.lock:
|
|
114
|
-
`;
|
|
115
|
-
|
|
116
|
-
const bundleGraph = await bundle('src/index.js', {inputFS: overlayFS});
|
|
117
|
-
|
|
118
|
-
const mainBundle = bundleGraph
|
|
119
|
-
.getBundles()
|
|
120
|
-
.find((b) => b.name === 'index.js');
|
|
121
|
-
if (!mainBundle) return assert(mainBundle);
|
|
122
|
-
|
|
123
|
-
const code = await overlayFS.readFile(mainBundle.filePath, 'utf-8');
|
|
124
|
-
assert.ok(
|
|
125
|
-
code.includes(
|
|
126
|
-
`require("e3ed71d88565db").getShardedBundleURL('b.8575baaf.js', ${maxShards}) + "b.8575baaf.js"`,
|
|
127
|
-
),
|
|
128
|
-
'Expected generated code for getShardedBundleURL was not found',
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
});
|