@atlaspack/runtime-js 2.15.0 → 2.15.2

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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @atlaspack/runtime-js
2
2
 
3
+ ## 2.15.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#702](https://github.com/atlassian-labs/atlaspack/pull/702) [`daaa768`](https://github.com/atlassian-labs/atlaspack/commit/daaa7688786772d7e3713b71c5bba6b89ec704aa) Thanks [@alshdavid](https://github.com/alshdavid)! - Fixes to Flow types
8
+
9
+ - Updated dependencies [[`daaa768`](https://github.com/atlassian-labs/atlaspack/commit/daaa7688786772d7e3713b71c5bba6b89ec704aa), [`1c7865a`](https://github.com/atlassian-labs/atlaspack/commit/1c7865a64451116d94015e248302435839d347c0), [`a0b959f`](https://github.com/atlassian-labs/atlaspack/commit/a0b959fbf61fc3f820ff03c7e8988945fe40a91a)]:
10
+ - @atlaspack/plugin@2.14.20
11
+ - @atlaspack/feature-flags@2.19.2
12
+ - @atlaspack/utils@2.17.2
13
+
14
+ ## 2.15.1
15
+
16
+ ### Patch Changes
17
+
18
+ - [#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
19
+
20
+ - Updated dependencies [[`13aef17`](https://github.com/atlassian-labs/atlaspack/commit/13aef177eea289a6e40d2113b5ec1ac9be18a33d)]:
21
+ - @atlaspack/feature-flags@2.19.1
22
+ - @atlaspack/utils@2.17.1
23
+ - @atlaspack/plugin@2.14.19
24
+
3
25
  ## 2.15.0
4
26
 
5
27
  ### 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 assetCode = `module.exports = require('../helpers/conditional-loader${options.mode === 'development' ? '-dev' : ''}')('${cond.key}', function (){return ${requireName}('${cond.ifTrueAssetId}')}, function (){return ${requireName}('${cond.ifFalseAssetId}')})`;
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/${cond.publicId}.js`),
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
@@ -270,7 +280,9 @@ var _default = exports.default = new (_plugin().Runtime)({
270
280
  }
271
281
 
272
282
  // URL dependency or not, fall back to including a runtime that exports the url
273
- assets.push(getURLRuntime(dependency, bundle, mainBundle, options, config.domainSharding));
283
+ assets.push(getURLRuntime(dependency, bundle, mainBundle, options,
284
+ // $FlowFixMe
285
+ config.domainSharding));
274
286
  }
275
287
 
276
288
  // In development, bundles can be created lazily. This means that the parent bundle may not
@@ -288,7 +300,9 @@ var _default = exports.default = new (_plugin().Runtime)({
288
300
  continue;
289
301
  }
290
302
  let relativePathExpr = getRelativePathExpr(bundle, referencedBundle, options);
291
- let loaderCode = `require(${JSON.stringify(loader)})(${getAbsoluteUrlExpr(relativePathExpr, bundle, config.domainSharding)})`;
303
+ let loaderCode = `require(${JSON.stringify(loader)})(${getAbsoluteUrlExpr(relativePathExpr, bundle,
304
+ // $FlowFixMe
305
+ config.domainSharding)})`;
292
306
  assets.push({
293
307
  filePath: __filename,
294
308
  code: loaderCode,
@@ -307,7 +321,9 @@ var _default = exports.default = new (_plugin().Runtime)({
307
321
  env: {
308
322
  sourceType: 'module'
309
323
  },
310
- priority: getManifestBundlePriority(bundleGraph, bundle, config.splitManifestThreshold)
324
+ priority: getManifestBundlePriority(bundleGraph, bundle,
325
+ // $FlowFixMe
326
+ config.splitManifestThreshold)
311
327
  });
312
328
  }
313
329
  return assets;
@@ -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 missing. Ensure the server sends the correct scripts to the client ("conditional-manifest.json").');
14
- throw err;
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
- return globalThis.__MCOND && globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
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.0",
3
+ "version": "2.15.2",
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.0",
21
- "@atlaspack/plugin": "2.14.18",
22
- "@atlaspack/utils": "2.17.0",
20
+ "@atlaspack/feature-flags": "2.19.2",
21
+ "@atlaspack/plugin": "2.14.20",
22
+ "@atlaspack/utils": "2.17.2",
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 assetCode = `module.exports = require('../helpers/conditional-loader${
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
- }')('${cond.key}', function (){return ${requireName}('${
227
- cond.ifTrueAssetId
228
- }')}, function (){return ${requireName}('${cond.ifFalseAssetId}')})`;
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/${cond.publicId}.js`),
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
@@ -296,6 +329,7 @@ export default (new Runtime({
296
329
  bundle,
297
330
  mainBundle,
298
331
  options,
332
+ // $FlowFixMe
299
333
  config.domainSharding,
300
334
  ),
301
335
  );
@@ -327,6 +361,7 @@ export default (new Runtime({
327
361
  )})(${getAbsoluteUrlExpr(
328
362
  relativePathExpr,
329
363
  bundle,
364
+ // $FlowFixMe
330
365
  config.domainSharding,
331
366
  )})`;
332
367
  assets.push({
@@ -353,6 +388,7 @@ export default (new Runtime({
353
388
  priority: getManifestBundlePriority(
354
389
  bundleGraph,
355
390
  bundle,
391
+ // $FlowFixMe
356
392
  config.splitManifestThreshold,
357
393
  ),
358
394
  });
@@ -360,7 +396,7 @@ export default (new Runtime({
360
396
 
361
397
  return assets;
362
398
  },
363
- }): Runtime);
399
+ }): Runtime<JSRuntimeConfig>);
364
400
 
365
401
  function getDependencies(bundle: NamedBundle): {|
366
402
  asyncDependencies: Array<Dependency>,
@@ -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 missing. Ensure the server sends the correct scripts to the client ("conditional-manifest.json").',
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
- throw err;
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
- return globalThis.__MCOND && globalThis.__MCOND(cond) ? ifTrue() : ifFalse();
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
  };