@atlaspack/runtime-js 2.15.0 → 2.15.1
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/CHANGELOG.md +11 -0
- package/lib/JSRuntime.js +12 -2
- package/lib/helpers/browser/sync-js-loader.js +33 -0
- package/lib/helpers/conditional-loader-dev.js +10 -3
- package/lib/helpers/conditional-loader.js +15 -2
- package/package.json +4 -4
- package/src/JSRuntime.js +38 -5
- package/src/helpers/browser/sync-js-loader.js +39 -0
- package/src/helpers/conditional-loader-dev.js +11 -3
- package/src/helpers/conditional-loader.js +18 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @atlaspack/runtime-js
|
|
2
2
|
|
|
3
|
+
## 2.15.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#692](https://github.com/atlassian-labs/atlaspack/pull/692) [`13aef17`](https://github.com/atlassian-labs/atlaspack/commit/13aef177eea289a6e40d2113b5ec1ac9be18a33d) Thanks [@JakeLane](https://github.com/JakeLane)! - Add fallback behaviour when conditional bundle is missing
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`13aef17`](https://github.com/atlassian-labs/atlaspack/commit/13aef177eea289a6e40d2113b5ec1ac9be18a33d)]:
|
|
10
|
+
- @atlaspack/feature-flags@2.19.1
|
|
11
|
+
- @atlaspack/utils@2.17.1
|
|
12
|
+
- @atlaspack/plugin@2.14.19
|
|
13
|
+
|
|
3
14
|
## 2.15.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/lib/JSRuntime.js
CHANGED
|
@@ -208,9 +208,19 @@ var _default = exports.default = new (_plugin().Runtime)({
|
|
|
208
208
|
const conditions = bundleGraph.getConditionsForDependencies(conditionalDependencies, bundle);
|
|
209
209
|
for (const cond of conditions) {
|
|
210
210
|
const requireName = (0, _featureFlags().getFeatureFlag)('hmrImprovements') || bundle.env.shouldScopeHoist ? 'parcelRequire' : '__parcel__require__';
|
|
211
|
-
const
|
|
211
|
+
const fallbackUrls = cond => {
|
|
212
|
+
return `[${[...cond.ifTrueBundles, ...cond.ifFalseBundles].map(target => {
|
|
213
|
+
let relativePathExpr = getRelativePathExpr(bundle, target, options);
|
|
214
|
+
return getAbsoluteUrlExpr(relativePathExpr, bundle, config.domainSharding);
|
|
215
|
+
}).join(',')}]`;
|
|
216
|
+
};
|
|
217
|
+
const shouldUseFallback = options.mode === 'development' ? (0, _featureFlags().getFeatureFlag)('condbDevFallbackDev') : (0, _featureFlags().getFeatureFlag)('condbDevFallbackProd');
|
|
218
|
+
const loaderPath = `./helpers/conditional-loader${options.mode === 'development' ? '-dev' : ''}`;
|
|
219
|
+
const ifTrue = `function (){return ${requireName}('${cond.ifTrueAssetId}')}`;
|
|
220
|
+
const ifFalse = `function (){return ${requireName}('${cond.ifFalseAssetId}')}`;
|
|
221
|
+
const assetCode = `module.exports = require('${loaderPath}')('${cond.key}', ${ifTrue}, ${ifFalse}${shouldUseFallback ? `, {loader: require('./helpers/browser/sync-js-loader'), urls: ${fallbackUrls(cond)}}` : ''})`;
|
|
212
222
|
assets.push({
|
|
213
|
-
filePath: _path().default.join(__dirname, `/conditions
|
|
223
|
+
filePath: _path().default.join(__dirname, `/conditions-${cond.publicId}.js`),
|
|
214
224
|
code: assetCode,
|
|
215
225
|
// This dependency is important, as it's the last symbol handled in scope hoisting.
|
|
216
226
|
// That means that scope hoisting will use the module id for this asset to replace the symbol
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const cacheLoader = require('../cacheLoader');
|
|
4
|
+
module.exports = function loadJSBundle(bundle) {
|
|
5
|
+
// Don't insert the same script twice (e.g. if it was already in the HTML)
|
|
6
|
+
let existingScripts = document.getElementsByTagName('script');
|
|
7
|
+
let isCurrentBundle = function (script) {
|
|
8
|
+
return script.src === bundle;
|
|
9
|
+
};
|
|
10
|
+
if ([].concat(existingScripts).some(isCurrentBundle)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Request using XHR because it's synchronous and we can't use promises here
|
|
15
|
+
// This has extremely poor performance because we're idle during this fetch, so we only use this so that the app won't crash
|
|
16
|
+
const xhr = new XMLHttpRequest();
|
|
17
|
+
xhr.open('GET', bundle, false);
|
|
18
|
+
try {
|
|
19
|
+
xhr.send();
|
|
20
|
+
if (xhr.status === 200) {
|
|
21
|
+
const script = document.createElement('script');
|
|
22
|
+
script.type = 'text/javascript';
|
|
23
|
+
script.text = xhr.responseText;
|
|
24
|
+
|
|
25
|
+
// Execute the script synchronously
|
|
26
|
+
document.head.appendChild(script);
|
|
27
|
+
} else {
|
|
28
|
+
throw new TypeError(`Failed to fetch dynamically imported module: ${bundle}. Status: ${xhr.status}`);
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
throw new TypeError(`Failed to fetch dynamically imported module: ${bundle}. Error: ${e.message}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
3
|
+
module.exports = function loadCond(cond, ifTrue, ifFalse, fallback) {
|
|
4
4
|
if (typeof globalThis.__MCOND !== 'function') {
|
|
5
5
|
throw new TypeError('"globalThis.__MCOND" was not set to an object. Ensure the function is set to return the key condition for conditional bundles to load with.');
|
|
6
6
|
}
|
|
@@ -10,7 +10,14 @@ module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
|
10
10
|
try {
|
|
11
11
|
return globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
|
|
12
12
|
} catch (err) {
|
|
13
|
-
console.error('Conditional dependency was
|
|
14
|
-
|
|
13
|
+
console.error('Conditional dependency was not registered when executing. Ensure the server sends the correct scripts to the client. Falling back to synchronous bundle loading.');
|
|
14
|
+
if (fallback) {
|
|
15
|
+
for (const url of fallback.urls) {
|
|
16
|
+
fallback.loader(url);
|
|
17
|
+
}
|
|
18
|
+
return globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
|
|
19
|
+
} else {
|
|
20
|
+
throw new Error('No fallback urls specified, cannot fallback safely');
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
};
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
4
|
-
|
|
3
|
+
module.exports = function loadCond(cond, ifTrue, ifFalse, fallback) {
|
|
4
|
+
let result = globalThis.__MCOND(cond);
|
|
5
|
+
try {
|
|
6
|
+
return result ? ifTrue() : ifFalse();
|
|
7
|
+
} catch (err) {
|
|
8
|
+
if (fallback) {
|
|
9
|
+
console.error('Conditional dependency was not registered when executing. Falling back to synchronous bundle loading.');
|
|
10
|
+
for (const url of fallback.urls) {
|
|
11
|
+
fallback.loader(url);
|
|
12
|
+
}
|
|
13
|
+
return result ? ifTrue() : ifFalse();
|
|
14
|
+
} else {
|
|
15
|
+
throw err;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
5
18
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/runtime-js",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.1",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@atlaspack/diagnostic": "2.14.1",
|
|
19
19
|
"@atlaspack/domain-sharding": "2.14.1",
|
|
20
|
-
"@atlaspack/feature-flags": "2.19.
|
|
21
|
-
"@atlaspack/plugin": "2.14.
|
|
22
|
-
"@atlaspack/utils": "2.17.
|
|
20
|
+
"@atlaspack/feature-flags": "2.19.1",
|
|
21
|
+
"@atlaspack/plugin": "2.14.19",
|
|
22
|
+
"@atlaspack/utils": "2.17.1",
|
|
23
23
|
"nullthrows": "^1.1.1"
|
|
24
24
|
},
|
|
25
25
|
"type": "commonjs"
|
package/src/JSRuntime.js
CHANGED
|
@@ -221,14 +221,47 @@ export default (new Runtime({
|
|
|
221
221
|
? 'parcelRequire'
|
|
222
222
|
: '__parcel__require__';
|
|
223
223
|
|
|
224
|
-
const
|
|
224
|
+
const fallbackUrls = (cond) => {
|
|
225
|
+
return `[${[...cond.ifTrueBundles, ...cond.ifFalseBundles]
|
|
226
|
+
.map((target) => {
|
|
227
|
+
let relativePathExpr = getRelativePathExpr(
|
|
228
|
+
bundle,
|
|
229
|
+
target,
|
|
230
|
+
options,
|
|
231
|
+
);
|
|
232
|
+
return getAbsoluteUrlExpr(
|
|
233
|
+
relativePathExpr,
|
|
234
|
+
bundle,
|
|
235
|
+
config.domainSharding,
|
|
236
|
+
);
|
|
237
|
+
})
|
|
238
|
+
.join(',')}]`;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const shouldUseFallback =
|
|
242
|
+
options.mode === 'development'
|
|
243
|
+
? getFeatureFlag('condbDevFallbackDev')
|
|
244
|
+
: getFeatureFlag('condbDevFallbackProd');
|
|
245
|
+
|
|
246
|
+
const loaderPath = `./helpers/conditional-loader${
|
|
225
247
|
options.mode === 'development' ? '-dev' : ''
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
248
|
+
}`;
|
|
249
|
+
|
|
250
|
+
const ifTrue = `function (){return ${requireName}('${cond.ifTrueAssetId}')}`;
|
|
251
|
+
const ifFalse = `function (){return ${requireName}('${cond.ifFalseAssetId}')}`;
|
|
252
|
+
|
|
253
|
+
const assetCode = `module.exports = require('${loaderPath}')('${
|
|
254
|
+
cond.key
|
|
255
|
+
}', ${ifTrue}, ${ifFalse}${
|
|
256
|
+
shouldUseFallback
|
|
257
|
+
? `, {loader: require('./helpers/browser/sync-js-loader'), urls: ${fallbackUrls(
|
|
258
|
+
cond,
|
|
259
|
+
)}}`
|
|
260
|
+
: ''
|
|
261
|
+
})`;
|
|
229
262
|
|
|
230
263
|
assets.push({
|
|
231
|
-
filePath: path.join(__dirname, `/conditions
|
|
264
|
+
filePath: path.join(__dirname, `/conditions-${cond.publicId}.js`),
|
|
232
265
|
code: assetCode,
|
|
233
266
|
// This dependency is important, as it's the last symbol handled in scope hoisting.
|
|
234
267
|
// That means that scope hoisting will use the module id for this asset to replace the symbol
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const cacheLoader = require('../cacheLoader');
|
|
2
|
+
|
|
3
|
+
module.exports = function loadJSBundle(bundle) {
|
|
4
|
+
// Don't insert the same script twice (e.g. if it was already in the HTML)
|
|
5
|
+
let existingScripts = document.getElementsByTagName('script');
|
|
6
|
+
let isCurrentBundle = function (script) {
|
|
7
|
+
return script.src === bundle;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
if ([].concat(existingScripts).some(isCurrentBundle)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Request using XHR because it's synchronous and we can't use promises here
|
|
15
|
+
// This has extremely poor performance because we're idle during this fetch, so we only use this so that the app won't crash
|
|
16
|
+
const xhr = new XMLHttpRequest();
|
|
17
|
+
xhr.open('GET', bundle, false);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
xhr.send();
|
|
21
|
+
|
|
22
|
+
if (xhr.status === 200) {
|
|
23
|
+
const script = document.createElement('script');
|
|
24
|
+
script.type = 'text/javascript';
|
|
25
|
+
script.text = xhr.responseText;
|
|
26
|
+
|
|
27
|
+
// Execute the script synchronously
|
|
28
|
+
document.head.appendChild(script);
|
|
29
|
+
} else {
|
|
30
|
+
throw new TypeError(
|
|
31
|
+
`Failed to fetch dynamically imported module: ${bundle}. Status: ${xhr.status}`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
} catch (e) {
|
|
35
|
+
throw new TypeError(
|
|
36
|
+
`Failed to fetch dynamically imported module: ${bundle}. Error: ${e.message}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
1
|
+
module.exports = function loadCond(cond, ifTrue, ifFalse, fallback) {
|
|
2
2
|
if (typeof globalThis.__MCOND !== 'function') {
|
|
3
3
|
throw new TypeError(
|
|
4
4
|
'"globalThis.__MCOND" was not set to an object. Ensure the function is set to return the key condition for conditional bundles to load with.',
|
|
@@ -15,9 +15,17 @@ module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
|
15
15
|
return globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
|
|
16
16
|
} catch (err) {
|
|
17
17
|
console.error(
|
|
18
|
-
'Conditional dependency was
|
|
18
|
+
'Conditional dependency was not registered when executing. Ensure the server sends the correct scripts to the client. Falling back to synchronous bundle loading.',
|
|
19
19
|
);
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
if (fallback) {
|
|
22
|
+
for (const url of fallback.urls) {
|
|
23
|
+
fallback.loader(url);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error('No fallback urls specified, cannot fallback safely');
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
31
|
};
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
module.exports = function loadCond(cond, ifTrue, ifFalse) {
|
|
2
|
-
|
|
1
|
+
module.exports = function loadCond(cond, ifTrue, ifFalse, fallback) {
|
|
2
|
+
let result = globalThis.__MCOND(cond);
|
|
3
|
+
try {
|
|
4
|
+
return result ? ifTrue() : ifFalse();
|
|
5
|
+
} catch (err) {
|
|
6
|
+
if (fallback) {
|
|
7
|
+
console.error(
|
|
8
|
+
'Conditional dependency was not registered when executing. Falling back to synchronous bundle loading.',
|
|
9
|
+
);
|
|
10
|
+
for (const url of fallback.urls) {
|
|
11
|
+
fallback.loader(url);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return result ? ifTrue() : ifFalse();
|
|
15
|
+
} else {
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
3
19
|
};
|