@studyportals/webpack-helper 6.0.7-17 → 6.0.7-18

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/README.md CHANGED
@@ -6,6 +6,10 @@ WebpackHelper is a utility that makes it easy to set up a webpack configuration
6
6
  - [Webpack version](#webpack-version)
7
7
  - [Notes on updating Webpack from v4 to v5](#notes-on-updating-webpack-from-v4-to-v5)
8
8
  - [Quick Start](#quick-start)
9
+ - [Chunks Retry](#chunks-retry)
10
+ - [Defaults](#defaults)
11
+ - [Configuration](#configuration)
12
+ - [Limitations](#limitations)
9
13
  - [Configuration](#configuration)
10
14
  - [entry](#entry-required)
11
15
  - [output](#output-required)
@@ -123,6 +127,54 @@ When your configuration is created you can get an instance of it for the correct
123
127
  ```javascript
124
128
  module.exports = (env, details) => configuration.get(details.mode);
125
129
  ```
130
+
131
+ ## Chunks Retry
132
+ Webpack Helpers has a default configuration to retry chunks which cannot get loaded on the first try (for whatever reason, network or otherwise).
133
+
134
+ It has an Exponential Backoff to calculate the delay between retries of a maximum of `2` seconds.
135
+
136
+ The functionality is implemented thru a plugin called `webpack-retry-chunk-load-plugin` https://www.npmjs.com/package/webpack-retry-chunk-load-plugin.
137
+
138
+ ### Defaults
139
+
140
+ By default it is enabled if the selected preset is `vue-typescript` and it uses `6` as the number of retries it does and it uses the `rollbar` instance on the `window` object (Portal instance) to log an error when it reaches the threshold of retries without being able to load the chunk (`new Error('Failed to load chunk for after retries')`).
141
+
142
+ ### Configuration
143
+ To configure the functionality you can provide an object following this interface
144
+ ```js
145
+ interface IChunksRetryPluginConfig {
146
+ inject: boolean; //if you want the plugin injected
147
+
148
+ threshold: number; //amount of retries
149
+
150
+ thresholdReachedCallBack?: string; //a function (body of it as string) to be called when the amount of retries has been exhausted
151
+
152
+ rollbarInstanceIdentifier?: string; //a key of a Rollbar instance present on the 'window' object e.g if you want to use window['rollbar_PQ'] to track the error in the Profile Questionnaire project in Rollbar then you send 'rollbar_PQ'
153
+
154
+ disableDefaultRollbarError?: boolean; //if you don't want to log by default when the threshold has been reached
155
+ }
156
+ ```
157
+
158
+ and you can provide this thru the `webpack` config of your service like so
159
+
160
+ ```js
161
+ const configuration = WebpackHelper.create({
162
+ chunksRetryConfig: {
163
+ threshold: 10,
164
+ thresholdReachedCallBack: `console.log("hello")`,
165
+ },
166
+ ...
167
+ ```
168
+
169
+ ### Limitations
170
+ We have some limitations in this implementation based on the plugin we used and that the code will be part of the webpack exported code
171
+
172
+ ### Only use ES5
173
+ You can only write ES5 code inside the `thresholdReachedCallBack`
174
+
175
+ ### String as function
176
+ The function `thresholdReachedCallBack` must be a string (aka the body of the function) and we cannot change that to be a function while retaining the simplicity of the code.
177
+
126
178
  ## Configuration
127
179
 
128
180
  Webpack Helper offers a compact but flexible configuration interface. Below you will find every option available.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studyportals/webpack-helper",
3
- "version": "6.0.7-17",
3
+ "version": "6.0.7-18",
4
4
  "description": "A collection of standard configurations and helpers for webpack.",
5
5
  "main": "src/main.js",
6
6
  "scripts": {
@@ -32,6 +32,7 @@
32
32
  "fork-ts-checker-webpack-plugin": "^9.0.2",
33
33
  "mini-css-extract-plugin": "^2.8.0",
34
34
  "path": "^0.12.7",
35
+ "prettier": "^3.4.2",
35
36
  "sass": "^1.71.1",
36
37
  "sass-loader": "^14.1.1",
37
38
  "terser-webpack-plugin": "^5.3.10",
@@ -39,8 +40,7 @@
39
40
  "vue-loader": "^17.4.2",
40
41
  "webpack": "^5.90.3",
41
42
  "webpack-cli": "^5.1.4",
42
- "webpack-merge": "^5.10.0",
43
- "webpack-retry-chunk-load-plugin": "^3.1.1"
43
+ "webpack-merge": "^5.10.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^20.11.20",
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin');
3
+ const mode_1 = require("../enums/mode");
4
+ const retry_chunk_load_plugin_1 = require("../plugins/retry-chunk-load.plugin");
4
5
  class ChunksRetryPluginFactory {
5
6
  static IsPresetSupported(preset) {
6
7
  if (!preset.retryChunksConfig)
7
8
  return false;
8
- // if (preset.mode === Mode.DEVELOPMENT) return false;
9
+ if (preset.mode === mode_1.Mode.DEVELOPMENT)
10
+ return false;
9
11
  if (!preset.retryChunksConfig.inject)
10
12
  return false;
11
13
  return true;
@@ -15,7 +17,7 @@ class ChunksRetryPluginFactory {
15
17
  }
16
18
  static CustomRetryChunksPlugin(preset) {
17
19
  const { retryChunksConfig } = preset;
18
- return new RetryChunkLoadPlugin({
20
+ return new retry_chunk_load_plugin_1.RetryChunkLoadPlugin({
19
21
  cacheBust: `function() {
20
22
  return Date.now();
21
23
  }`,
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RetryChunkLoadPlugin = void 0;
37
+ const prettier = __importStar(require("prettier"));
38
+ const webpack_1 = require("webpack");
39
+ const pluginName = 'RetryChunkLoadPlugin';
40
+ class RetryChunkLoadPlugin {
41
+ constructor(options = {}) {
42
+ this.options = Object.assign({}, options);
43
+ }
44
+ apply(compiler) {
45
+ compiler.hooks.thisCompilation.tap(pluginName, compilation => {
46
+ const { mainTemplate, runtimeTemplate } = compilation;
47
+ const maxRetryValueFromOptions = Number(this.options.maxRetries);
48
+ const maxRetries = Number.isInteger(maxRetryValueFromOptions) &&
49
+ maxRetryValueFromOptions > 0
50
+ ? maxRetryValueFromOptions
51
+ : 1;
52
+ const getCacheBustString = () => this.options.cacheBust
53
+ ? `
54
+ (${this.options.cacheBust})();
55
+ `
56
+ : '"cache-bust=true"';
57
+ mainTemplate.hooks.localVars.tap({ name: pluginName, stage: 1 }, (source, chunk) => {
58
+ const currentChunkName = chunk.name;
59
+ const addRetryCode = !this.options.chunks ||
60
+ this.options.chunks.some(chunk => chunk === currentChunkName);
61
+ const getRetryDelay = typeof this.options.retryDelay === 'string'
62
+ ? this.options.retryDelay
63
+ : `function() { return ${this.options.retryDelay || 0} }`;
64
+ if (!addRetryCode)
65
+ return source;
66
+ const script = runtimeTemplate.iife('', `
67
+ if(typeof ${webpack_1.RuntimeGlobals.require} !== "undefined") {
68
+ var oldGetScript = ${webpack_1.RuntimeGlobals.getChunkScriptFilename};
69
+ var oldLoadScript = ${webpack_1.RuntimeGlobals.ensureChunk};
70
+ var queryMap = {};
71
+ var countMap = {};
72
+ var getRetryDelay = ${getRetryDelay}
73
+ ${webpack_1.RuntimeGlobals.getChunkScriptFilename} = function(chunkId){
74
+ var result = oldGetScript(chunkId);
75
+ return result + (queryMap.hasOwnProperty(chunkId) ? '?' + queryMap[chunkId] : '');
76
+ };
77
+ ${webpack_1.RuntimeGlobals.ensureChunk} = function(chunkId){
78
+ var result = oldLoadScript(chunkId);
79
+ return result.catch(function(error){
80
+ var retries = countMap.hasOwnProperty(chunkId) ? countMap[chunkId] : ${maxRetries};
81
+ if (retries < 1) {
82
+ var realSrc = oldGetScript(chunkId);
83
+ error.message = 'Loading chunk ' + chunkId + ' failed after ${maxRetries} retries.\\n(' + realSrc + ')';
84
+ error.request = realSrc;${this.options.lastResortScript
85
+ ? this.options.lastResortScript
86
+ : ''}
87
+ throw error;
88
+ }
89
+ return new Promise(function (resolve) {
90
+ var retryAttempt = ${maxRetries} - retries + 1;
91
+ setTimeout(function () {
92
+ var retryAttemptString = '&retry-attempt=' + retryAttempt;
93
+ var cacheBust = ${getCacheBustString()} + retryAttemptString;
94
+ queryMap[chunkId] = cacheBust;
95
+ countMap[chunkId] = retries - 1;
96
+ resolve(${webpack_1.RuntimeGlobals.ensureChunk}(chunkId));
97
+ }, getRetryDelay(retryAttempt))
98
+ })
99
+ });
100
+ };
101
+ }`);
102
+ return (source +
103
+ prettier.format(script, {
104
+ trailingComma: 'es5',
105
+ singleQuote: true,
106
+ parser: 'babel',
107
+ }));
108
+ });
109
+ });
110
+ }
111
+ }
112
+ exports.RetryChunkLoadPlugin = RetryChunkLoadPlugin;