├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── docs └── reloadImg.png ├── package-lock.json ├── package.json ├── src └── index.js └── test ├── .eslintrc.js ├── base.webpack.config.js ├── import-retry ├── async.js ├── entry.js ├── styles.css └── webpack.config.js ├── test.js └── tmp ├── 0.ef67cb71a0c4c266fffe.css ├── index.html ├── main.e56c4442df65c37513da.js └── runtime~main.f5c247a9a03eec592f28.js /.eslintignore: -------------------------------------------------------------------------------- 1 | test/tmp 2 | !.*.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2016 5 | }, 6 | env: { 7 | es6: true, 8 | node: true 9 | }, 10 | extends: ["plugin:prettier/recommended"], 11 | 12 | rules: { 13 | // http://eslint.org/docs/rules/no-param-reassign 14 | // Allow param reassign. We need to do this a lot in the plugin 15 | "no-param-reassign": ["off"], 16 | 17 | // http://eslint.org/docs/rules/no-underscore-dangle 18 | // Allow references starting with underscore. Webpack has those. 19 | "no-underscore-dangle": ["off"] 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !src/* 3 | !AUTHORS 4 | !CHANGELOG.md 5 | !CODE_OF_CONDUCT.md 6 | !LICENSE.txt 7 | !README.md -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | cache: yarn 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Tests", 11 | "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", 12 | "args": [ 13 | "-u", 14 | "tdd", 15 | "--timeout", 16 | "999999", 17 | "--colors", 18 | "${workspaceRoot}/test" 19 | ], 20 | "internalConsoleOptions": "openOnSessionStart" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 WilsonLiu95 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webpack-plugin-import-retry 2 | 3 | webpack plugin to modify webpack_require module to retry import async chunk again 4 | 5 | `webpack` 插件,修改 `webpack`内置的脚本加载器,达到 `import` 时,如果加载异常,进行资源请求重试。 6 | 7 | ## Installation 8 | 9 | With npm 10 | 11 | ```shell 12 | npm install webpack-plugin-import-retry --save-dev 13 | ``` 14 | 15 | With yarn 16 | 17 | ```shell 18 | yarn add webpack-plugin-import-retry --dev 19 | ``` 20 | 21 | ## 截图 screenshot 22 | 23 | ![retry JS](./docs/reloadImg.png) 24 | 25 | ## Usage 26 | 27 | Just add this plugin as usual. 28 | 29 | ```javascript 30 | // webpack.config.js 31 | const importRetry = require("webpack-plugin-import-retry"); 32 | 33 | module.exports = { 34 | // ... 35 | output: { 36 | //... 37 | filename: "[name].[chunkhash].js" 38 | }, 39 | plugins: [new importRetry(options)] 40 | }; 41 | ``` 42 | 43 | ## why? 44 | 45 | 许多时候用户网络较差,导致请求资源时失败,在用户量较大的时候这个问题会更加明显。 46 | 47 | 同时也会因为各种问题导致 CDN 域名不可访问,此时可降级请求当前域名的资源,可访问成功。 48 | 49 | 因此,资源重试显得非常有必要,这个事情可以通过封装 `import()` 完成,大家共同调用封装后的函数,但是需要大家都遵守规范。 50 | 51 | 这种方式也不利于使用 注释的功能 即 `import(/* webpackChunkName: "floatIndex" */'./views/floatIndex.vue')`。 52 | 53 | 因此,更好的解决方案,可以采用改写`webpack`异步加载的 `requireEnsure`函数来实现。 54 | 55 | 本插件即改写了 `requireEnsure`来实现,资源加载失败,重试 2 次,第二次采用当前域名的方式来实现。 56 | 57 | 针对一个`chunk`包含`css`与`js`两块资源的时候,两者任一资源重试 2 次失败则不再进行重试。 58 | 59 | ## Options 60 | 61 | ### options.cdnDomain 62 | 63 | 有值且未传入 `fmtRequireUrlFuncStr` 时,默认第二次重载时将 `cdnDomain` 替换为 `location.hostname` 64 | 65 | ### options.fmtRequireUrlFuncStr 66 | 67 | 格式化资源 `URL`,传入则会替换默认的格式化函数。 68 | 69 | 入参 70 | 71 | ```javascript 72 | // 默认的函数 73 | function(htmlNode, chunkId, __webpack_require__, options){ 74 | var modifyReloadQry = function(url, reloadTimes){ 75 | if(/reloadAssets=(\d+)&?/.test(url)){ 76 | return url.replace('reloadAssets='+reloadTimes, 'reloadAssets='+(1+reloadTimes)); 77 | } 78 | return url + (url.indexOf('?')!=-1 ? '&':'?') + 'reloadAssets='+(reloadTimes+1); 79 | } 80 | options = options || { 81 | LINK: 0, 82 | SCRIPT: 0 83 | }; 84 | var nodeName = htmlNode.nodeName; 85 | var reloadTimes = options[nodeName] || 0; 86 | var linkKey = 'src'; 87 | if(nodeName =='LINK'){ 88 | linkKey = 'href'; 89 | } 90 | if(!htmlNode[linkKey]) return; 91 | if(reloadTimes == 0 || reloadTimes > 2) return; 92 | var replaceUrl = modifyReloadQry(htmlNode[linkKey], reloadTimes-1); 93 | htmlNode[linkKey] = replaceUrl; 94 | } 95 | } 96 | ``` 97 | 98 | ## 对于其他资源,可以配合 assets-reload? 99 | 100 | 另外一个资源加载重试的组件 [assets-reload](https://www.npmjs.com/package/assets-reload) 101 | 本模块通过 script, link, img 等标签上的 onerror 回调来进行资源加载重试,并且规则可定制。 102 | -------------------------------------------------------------------------------- /docs/reloadImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WilsonLiu95/webpack-plugin-import-retry/62a786dcd7cc4b2d111bca567602b8b1c472bdf0/docs/reloadImg.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-plugin-import-retry", 3 | "version": "1.0.2", 4 | "description": "webpack plugin to modify webpack_require module to retry import async chunk again", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "lint": "eslint . --fix", 8 | "test": "mocha --reporter spec test/*.js && eslint .", 9 | "clean": "rm -fr test/tmp" 10 | }, 11 | "author": "wilsonsliu ", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "chai": "^4.2.0", 15 | "css-loader": "^1.0.1", 16 | "eslint": "^5.9.0", 17 | "eslint-config-airbnb-base": "^13.1.0", 18 | "eslint-config-prettier": "^3.3.0", 19 | "eslint-plugin-import": "^2.14.0", 20 | "eslint-plugin-mocha": "^5.2.0", 21 | "eslint-plugin-prettier": "^3.0.0", 22 | "html-webpack-plugin": "^3.0.6", 23 | "mini-css-extract-plugin": "^0.4.5", 24 | "mocha": "^5.2.0", 25 | "prettier": "^1.15.2", 26 | "rimraf": "^2.6.2", 27 | "sinon": "^7.1.1", 28 | "webpack": "^4.26.0", 29 | "webpack-cli": "^3.1.2" 30 | }, 31 | "dependencies": {}, 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/WilsonLiu95/webpack-plugin-import-retry" 35 | }, 36 | "keywords": [ 37 | "webpack", 38 | "plugin", 39 | "import", 40 | "retry", 41 | "again" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | class AssetReload { 3 | constructor({ fmtRequireUrlFuncStr, cdnDomain } = {}) { 4 | this.options = { 5 | fmtRequireUrlFuncStr: `function (htmlNode, chunkId, __webpack_require__, options){ 6 | var modifyReloadQry = function(url, reloadTimes){ 7 | if(/reloadAssets=(\d+)&?/.test(url)){ 8 | return url.replace('reloadAssets='+reloadTimes, 'reloadAssets='+(1+reloadTimes)); 9 | } 10 | return url + (url.indexOf('?')!=-1 ? '&':'?') + 'reloadAssets='+(reloadTimes+1); 11 | } 12 | options = options || { 13 | LINK: 0, 14 | SCRIPT: 0 15 | }; 16 | var nodeName = htmlNode.nodeName; 17 | var reloadTimes = options[nodeName] || 0; 18 | var linkKey = 'src'; 19 | if(nodeName =='LINK'){ 20 | linkKey = 'href'; 21 | } 22 | if(!htmlNode[linkKey]) return; 23 | if(reloadTimes == 0 || reloadTimes > 2) return; 24 | var replaceUrl = modifyReloadQry(htmlNode[linkKey], reloadTimes-1); 25 | ${ 26 | cdnDomain 27 | ? "if(reloadTimes == 2){replaceUrl = replaceUrl.replace('" + 28 | cdnDomain + 29 | "', location.hostname)}" 30 | : "" 31 | } 32 | 33 | htmlNode[linkKey] = replaceUrl; 34 | }` 35 | }; 36 | if (fmtRequireUrlFuncStr) { 37 | this.options.fmtRequireUrlFuncStr = 38 | typeof fmtRequireUrlFuncStr == "function" 39 | ? fmtRequireUrlFuncStr.toString() 40 | : fmtRequireUrlFuncStr; 41 | } 42 | } 43 | apply(compiler) { 44 | compiler.hooks.compilation.tap("MyPlugin", compilation => { 45 | const { Template } = webpack; 46 | const { mainTemplate } = compilation; 47 | mainTemplate.hooks.requireExtensions.tap("assets-reload", source => { 48 | // hack requireEnsure add options params 49 | return source.replace( 50 | "function requireEnsure(chunkId) {", 51 | "function requireEnsure(chunkId, options) {" 52 | ); 53 | }); 54 | mainTemplate.hooks.bootstrap.tap("assets-reload", source => { 55 | if (!source) { 56 | return; 57 | } 58 | // add fmtRequireUrl function 59 | return Template.asString([ 60 | source, 61 | `window.fmtRequireUrl = ${this.options.fmtRequireUrlFuncStr}` 62 | ]); 63 | }); 64 | mainTemplate.hooks.beforeStartup.tap( 65 | "assets-reload", 66 | (source, chunk, hash) => { 67 | if (!source) { 68 | return; 69 | } 70 | // new RequireEnsure to reload again 71 | var newRequireEnsure = `function newRequireEnsure (chunkId, options) { 72 | return __webpack_require__.oldE(chunkId, options).then(function () {}, function (err) { 73 | console.error(err); 74 | var type; 75 | if (/.*\.css\??/.test(err.request)) { 76 | type = 'LINK'; 77 | } else if (/.*\.js\??.*/.test(err.request)) { 78 | type = 'SCRIPT'; 79 | } 80 | if (options === undefined) { 81 | options = { 82 | LINK: 0, 83 | SCRIPT: 0 84 | }; 85 | } 86 | options[type]++; 87 | // 最小值为1 88 | if (options[type] <= 2) { 89 | return newRequireEnsure(chunkId, options); 90 | } 91 | }) 92 | }`; 93 | 94 | return Template.asString([ 95 | source, 96 | "__webpack_require__.oldE = __webpack_require__.e;", 97 | `__webpack_require__.e = ${newRequireEnsure}` 98 | ]); 99 | } 100 | ); 101 | 102 | mainTemplate.hooks.requireEnsure.tap( 103 | "assets-reload", 104 | (source, chunk, hash) => { 105 | // hack fmtRequireUrl 106 | const cssHackReplace = "linkTag.href = fullhref;"; 107 | 108 | source = source.replace( 109 | cssHackReplace, 110 | Template.asString([ 111 | cssHackReplace, 112 | `window.fmtRequireUrl && window.fmtRequireUrl(linkTag, chunkId, __webpack_require__, options);` 113 | ]) 114 | ); 115 | const jsHackReplace = "script.src = jsonpScriptSrc(chunkId);"; 116 | source = source.replace( 117 | jsHackReplace, 118 | Template.asString([ 119 | jsHackReplace, 120 | `window.fmtRequireUrl && fmtRequireUrl(script, chunkId, __webpack_require__, options);` 121 | ]) 122 | ); 123 | return source; 124 | } 125 | ); 126 | }); 127 | } 128 | } 129 | module.exports = AssetReload; 130 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | mocha: true 4 | }, 5 | plugins: ["mocha"], 6 | rules: { 7 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-dynamic-require.md 8 | // Allow dynamic require(), we use it in the tests 9 | "import/no-dynamic-require": ["off"], 10 | 11 | // https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-exclusive-tests.md 12 | // Disallow .only tests 13 | "mocha/no-exclusive-tests": ["error"] 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /test/base.webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const rel = paths => path.resolve(__dirname, ...paths); 3 | 4 | module.exports = { 5 | output: { 6 | path: rel`./tmp`, 7 | filename: "[name].[chunkhash].js" 8 | }, 9 | 10 | // This is not required for the plugin to work, but it makes the tests easier because we can use 11 | // names instead of ids to address the chunks. 12 | optimization: { 13 | namedModules: true, 14 | namedChunks: true, 15 | minimize: false, 16 | runtimeChunk: true 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/import-retry/async.js: -------------------------------------------------------------------------------- 1 | /* global document */ 2 | const styles = require("./styles.css"); 3 | 4 | document.write(`These are the styles ${styles}`); 5 | -------------------------------------------------------------------------------- /test/import-retry/entry.js: -------------------------------------------------------------------------------- 1 | /* global document */ 2 | document.write("This is a test"); 3 | require.ensure([], require => { 4 | require("./async"); 5 | }); 6 | -------------------------------------------------------------------------------- /test/import-retry/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | content: 'mini-css-test'; 3 | } -------------------------------------------------------------------------------- /test/import-retry/webpack.config.js: -------------------------------------------------------------------------------- 1 | const importRetry = require("../../src/index.js"); 2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | const path = require("path"); 5 | const baseConfig = require("../base.webpack.config"); 6 | 7 | const rel = paths => path.resolve(__dirname, ...paths); 8 | 9 | module.exports = Object.assign({}, baseConfig, { 10 | entry: rel`./entry.js`, 11 | // devtool: "sourcemap", 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.css$/, 16 | use: [ 17 | MiniCssExtractPlugin.loader, 18 | { 19 | loader: "css-loader", 20 | options: { 21 | sourceMap: true, 22 | modules: true 23 | } 24 | } 25 | ] 26 | } 27 | ] 28 | }, 29 | plugins: [ 30 | new importRetry(), 31 | new HtmlWebpackPlugin({ 32 | filename: "index.html" 33 | }), 34 | new MiniCssExtractPlugin({ 35 | filename: "[name].[contenthash].css", 36 | chunkFilename: "[id].[contenthash].css" 37 | }) 38 | ] 39 | }); 40 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const crypto = require("crypto"); 2 | const webpack = require("webpack"); 3 | const path = require("path"); 4 | const { expect } = require("chai"); 5 | const rimraf = require("rimraf"); 6 | const fs = require("fs"); 7 | const sinon = require("sinon"); 8 | 9 | const webpackCompile = (fixture, mode) => 10 | new Promise((resolve, reject) => { 11 | const dir = path.resolve(__dirname, fixture); 12 | const config = path.resolve(dir, "webpack.config.js"); 13 | // eslint-disable-next-line global-require 14 | const opts = Object.assign(require(config), { 15 | mode, 16 | context: dir 17 | }); 18 | webpack(opts, (err, stats) => { 19 | if (err) reject(err); 20 | else resolve(stats); 21 | }); 22 | }); 23 | 24 | describe("OutputHash", () => { 25 | const modes = ["production"]; 26 | 27 | before(() => { 28 | if (fs.existsSync("./test/tmp")) { 29 | rimraf.sync("./test/tmp"); 30 | } 31 | }); 32 | 33 | afterEach(() => { 34 | sinon.restore(); 35 | }); 36 | 37 | modes.forEach(mode => { 38 | context(`In ${mode} mode`, () => { 39 | it("Works with mini-css-extract-plugin", () => 40 | webpackCompile("import-retry", mode).then(stats => { 41 | console.log(stats.assets); 42 | })); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/tmp/0.ef67cb71a0c4c266fffe.css: -------------------------------------------------------------------------------- 1 | html { 2 | content: 'mini-css-test'; 3 | } 4 | -------------------------------------------------------------------------------- /test/tmp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack App 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/tmp/main.e56c4442df65c37513da.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["main"],{ 2 | 3 | /***/ "./entry.js": 4 | /***/ (function(module, exports, __webpack_require__) { 5 | 6 | /* global document */ 7 | document.write("This is a test"); 8 | __webpack_require__.e(/* require.ensure */ 0).then((require => { 9 | __webpack_require__("./async.js"); 10 | }).bind(null, __webpack_require__)).catch(__webpack_require__.oe); 11 | 12 | 13 | /***/ }) 14 | 15 | },[["./entry.js","runtime~main"]]]); -------------------------------------------------------------------------------- /test/tmp/runtime~main.f5c247a9a03eec592f28.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // install a JSONP callback for chunk loading 3 | /******/ function webpackJsonpCallback(data) { 4 | /******/ var chunkIds = data[0]; 5 | /******/ var moreModules = data[1]; 6 | /******/ var executeModules = data[2]; 7 | /******/ 8 | /******/ // add "moreModules" to the modules object, 9 | /******/ // then flag all "chunkIds" as loaded and fire callback 10 | /******/ var moduleId, chunkId, i = 0, resolves = []; 11 | /******/ for(;i < chunkIds.length; i++) { 12 | /******/ chunkId = chunkIds[i]; 13 | /******/ if(installedChunks[chunkId]) { 14 | /******/ resolves.push(installedChunks[chunkId][0]); 15 | /******/ } 16 | /******/ installedChunks[chunkId] = 0; 17 | /******/ } 18 | /******/ for(moduleId in moreModules) { 19 | /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { 20 | /******/ modules[moduleId] = moreModules[moduleId]; 21 | /******/ } 22 | /******/ } 23 | /******/ if(parentJsonpFunction) parentJsonpFunction(data); 24 | /******/ 25 | /******/ while(resolves.length) { 26 | /******/ resolves.shift()(); 27 | /******/ } 28 | /******/ 29 | /******/ // add entry modules from loaded chunk to deferred list 30 | /******/ deferredModules.push.apply(deferredModules, executeModules || []); 31 | /******/ 32 | /******/ // run deferred modules when all chunks ready 33 | /******/ return checkDeferredModules(); 34 | /******/ }; 35 | /******/ function checkDeferredModules() { 36 | /******/ var result; 37 | /******/ for(var i = 0; i < deferredModules.length; i++) { 38 | /******/ var deferredModule = deferredModules[i]; 39 | /******/ var fulfilled = true; 40 | /******/ for(var j = 1; j < deferredModule.length; j++) { 41 | /******/ var depId = deferredModule[j]; 42 | /******/ if(installedChunks[depId] !== 0) fulfilled = false; 43 | /******/ } 44 | /******/ if(fulfilled) { 45 | /******/ deferredModules.splice(i--, 1); 46 | /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); 47 | /******/ } 48 | /******/ } 49 | /******/ return result; 50 | /******/ } 51 | /******/ window.fmtRequireUrl = function (htmlNode, chunkId, __webpack_require__, options){ 52 | /******/ var modifyReloadQry = function(url, reloadTimes){ 53 | /******/ if(/reloadAssets=(d+)&?/.test(url)){ 54 | /******/ return url.replace('reloadAssets='+reloadTimes, 'reloadAssets='+(1+reloadTimes)); 55 | /******/ } 56 | /******/ return url + (url.indexOf('?')!=-1 ? '&':'?') + 'reloadAssets='+(reloadTimes+1); 57 | /******/ } 58 | /******/ options = options || { 59 | /******/ LINK: 0, 60 | /******/ SCRIPT: 0 61 | /******/ }; 62 | /******/ var nodeName = htmlNode.nodeName; 63 | /******/ var reloadTimes = options[nodeName] || 0; 64 | /******/ var linkKey = 'src'; 65 | /******/ if(nodeName =='LINK'){ 66 | /******/ linkKey = 'href'; 67 | /******/ } 68 | /******/ if(!htmlNode[linkKey]) return; 69 | /******/ if(reloadTimes == 0 || reloadTimes > 2) return; 70 | /******/ var replaceUrl = modifyReloadQry(htmlNode[linkKey], reloadTimes-1); 71 | /******/ 72 | /******/ 73 | /******/ htmlNode[linkKey] = replaceUrl; 74 | /******/ } 75 | /******/ 76 | /******/ // The module cache 77 | /******/ var installedModules = {}; 78 | /******/ 79 | /******/ // object to store loaded CSS chunks 80 | /******/ var installedCssChunks = { 81 | /******/ "runtime~main": 0 82 | /******/ } 83 | /******/ 84 | /******/ // object to store loaded and loading chunks 85 | /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched 86 | /******/ // Promise = chunk loading, 0 = chunk loaded 87 | /******/ var installedChunks = { 88 | /******/ "runtime~main": 0 89 | /******/ }; 90 | /******/ 91 | /******/ var deferredModules = []; 92 | /******/ 93 | /******/ // script path function 94 | /******/ function jsonpScriptSrc(chunkId) { 95 | /******/ return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + "." + {"0":"6c2333a2fdab01662dcd"}[chunkId] + ".js" 96 | /******/ } 97 | /******/ 98 | /******/ // The require function 99 | /******/ function __webpack_require__(moduleId) { 100 | /******/ 101 | /******/ // Check if module is in cache 102 | /******/ if(installedModules[moduleId]) { 103 | /******/ return installedModules[moduleId].exports; 104 | /******/ } 105 | /******/ // Create a new module (and put it into the cache) 106 | /******/ var module = installedModules[moduleId] = { 107 | /******/ i: moduleId, 108 | /******/ l: false, 109 | /******/ exports: {} 110 | /******/ }; 111 | /******/ 112 | /******/ // Execute the module function 113 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 114 | /******/ 115 | /******/ // Flag the module as loaded 116 | /******/ module.l = true; 117 | /******/ 118 | /******/ // Return the exports of the module 119 | /******/ return module.exports; 120 | /******/ } 121 | /******/ 122 | /******/ // This file contains only the entry chunk. 123 | /******/ // The chunk loading function for additional chunks 124 | /******/ __webpack_require__.e = function requireEnsure(chunkId, options) { 125 | /******/ var promises = []; 126 | /******/ 127 | /******/ 128 | /******/ // mini-css-extract-plugin CSS loading 129 | /******/ var cssChunks = {"0":1}; 130 | /******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]); 131 | /******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) { 132 | /******/ promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) { 133 | /******/ var href = "" + chunkId + "." + {"0":"ef67cb71a0c4c266fffe"}[chunkId] + ".css"; 134 | /******/ var fullhref = __webpack_require__.p + href; 135 | /******/ var existingLinkTags = document.getElementsByTagName("link"); 136 | /******/ for(var i = 0; i < existingLinkTags.length; i++) { 137 | /******/ var tag = existingLinkTags[i]; 138 | /******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href"); 139 | /******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve(); 140 | /******/ } 141 | /******/ var existingStyleTags = document.getElementsByTagName("style"); 142 | /******/ for(var i = 0; i < existingStyleTags.length; i++) { 143 | /******/ var tag = existingStyleTags[i]; 144 | /******/ var dataHref = tag.getAttribute("data-href"); 145 | /******/ if(dataHref === href || dataHref === fullhref) return resolve(); 146 | /******/ } 147 | /******/ var linkTag = document.createElement("link"); 148 | /******/ linkTag.rel = "stylesheet"; 149 | /******/ linkTag.type = "text/css"; 150 | /******/ linkTag.onload = resolve; 151 | /******/ linkTag.onerror = function(event) { 152 | /******/ var request = event && event.target && event.target.src || fullhref; 153 | /******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + request + ")"); 154 | /******/ err.request = request; 155 | /******/ delete installedCssChunks[chunkId] 156 | /******/ linkTag.parentNode.removeChild(linkTag) 157 | /******/ reject(err); 158 | /******/ }; 159 | /******/ linkTag.href = fullhref; 160 | /******/ window.fmtRequireUrl && window.fmtRequireUrl(linkTag, chunkId, __webpack_require__, options); 161 | /******/ var head = document.getElementsByTagName("head")[0]; 162 | /******/ head.appendChild(linkTag); 163 | /******/ }).then(function() { 164 | /******/ installedCssChunks[chunkId] = 0; 165 | /******/ })); 166 | /******/ } 167 | /******/ 168 | /******/ // JSONP chunk loading for javascript 169 | /******/ 170 | /******/ var installedChunkData = installedChunks[chunkId]; 171 | /******/ if(installedChunkData !== 0) { // 0 means "already installed". 172 | /******/ 173 | /******/ // a Promise means "currently loading". 174 | /******/ if(installedChunkData) { 175 | /******/ promises.push(installedChunkData[2]); 176 | /******/ } else { 177 | /******/ // setup Promise in chunk cache 178 | /******/ var promise = new Promise(function(resolve, reject) { 179 | /******/ installedChunkData = installedChunks[chunkId] = [resolve, reject]; 180 | /******/ }); 181 | /******/ promises.push(installedChunkData[2] = promise); 182 | /******/ 183 | /******/ // start chunk loading 184 | /******/ var script = document.createElement('script'); 185 | /******/ var onScriptComplete; 186 | /******/ 187 | /******/ script.charset = 'utf-8'; 188 | /******/ script.timeout = 120; 189 | /******/ if (__webpack_require__.nc) { 190 | /******/ script.setAttribute("nonce", __webpack_require__.nc); 191 | /******/ } 192 | /******/ script.src = jsonpScriptSrc(chunkId); 193 | /******/ window.fmtRequireUrl && fmtRequireUrl(script, chunkId, __webpack_require__, options); 194 | /******/ 195 | /******/ onScriptComplete = function (event) { 196 | /******/ // avoid mem leaks in IE. 197 | /******/ script.onerror = script.onload = null; 198 | /******/ clearTimeout(timeout); 199 | /******/ var chunk = installedChunks[chunkId]; 200 | /******/ if(chunk !== 0) { 201 | /******/ if(chunk) { 202 | /******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); 203 | /******/ var realSrc = event && event.target && event.target.src; 204 | /******/ var error = new Error('Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')'); 205 | /******/ error.type = errorType; 206 | /******/ error.request = realSrc; 207 | /******/ chunk[1](error); 208 | /******/ } 209 | /******/ installedChunks[chunkId] = undefined; 210 | /******/ } 211 | /******/ }; 212 | /******/ var timeout = setTimeout(function(){ 213 | /******/ onScriptComplete({ type: 'timeout', target: script }); 214 | /******/ }, 120000); 215 | /******/ script.onerror = script.onload = onScriptComplete; 216 | /******/ document.head.appendChild(script); 217 | /******/ } 218 | /******/ } 219 | /******/ return Promise.all(promises); 220 | /******/ }; 221 | /******/ 222 | /******/ // expose the modules object (__webpack_modules__) 223 | /******/ __webpack_require__.m = modules; 224 | /******/ 225 | /******/ // expose the module cache 226 | /******/ __webpack_require__.c = installedModules; 227 | /******/ 228 | /******/ // define getter function for harmony exports 229 | /******/ __webpack_require__.d = function(exports, name, getter) { 230 | /******/ if(!__webpack_require__.o(exports, name)) { 231 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 232 | /******/ } 233 | /******/ }; 234 | /******/ 235 | /******/ // define __esModule on exports 236 | /******/ __webpack_require__.r = function(exports) { 237 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 238 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 239 | /******/ } 240 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 241 | /******/ }; 242 | /******/ 243 | /******/ // create a fake namespace object 244 | /******/ // mode & 1: value is a module id, require it 245 | /******/ // mode & 2: merge all properties of value into the ns 246 | /******/ // mode & 4: return value when already ns object 247 | /******/ // mode & 8|1: behave like require 248 | /******/ __webpack_require__.t = function(value, mode) { 249 | /******/ if(mode & 1) value = __webpack_require__(value); 250 | /******/ if(mode & 8) return value; 251 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 252 | /******/ var ns = Object.create(null); 253 | /******/ __webpack_require__.r(ns); 254 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 255 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 256 | /******/ return ns; 257 | /******/ }; 258 | /******/ 259 | /******/ // getDefaultExport function for compatibility with non-harmony modules 260 | /******/ __webpack_require__.n = function(module) { 261 | /******/ var getter = module && module.__esModule ? 262 | /******/ function getDefault() { return module['default']; } : 263 | /******/ function getModuleExports() { return module; }; 264 | /******/ __webpack_require__.d(getter, 'a', getter); 265 | /******/ return getter; 266 | /******/ }; 267 | /******/ 268 | /******/ // Object.prototype.hasOwnProperty.call 269 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 270 | /******/ 271 | /******/ // __webpack_public_path__ 272 | /******/ __webpack_require__.p = ""; 273 | /******/ 274 | /******/ // on error function for async loading 275 | /******/ __webpack_require__.oe = function(err) { console.error(err); throw err; }; 276 | /******/ 277 | /******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; 278 | /******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); 279 | /******/ jsonpArray.push = webpackJsonpCallback; 280 | /******/ jsonpArray = jsonpArray.slice(); 281 | /******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); 282 | /******/ var parentJsonpFunction = oldJsonpFunction; 283 | /******/ 284 | /******/ 285 | /******/ __webpack_require__.oldE = __webpack_require__.e; 286 | /******/ __webpack_require__.e = function newRequireEnsure (chunkId, options) { 287 | /******/ return __webpack_require__.oldE(chunkId, options).then(function () {}, function (err) { 288 | /******/ console.error(err); 289 | /******/ var type; 290 | /******/ if (/.*.css??/.test(err.request)) { 291 | /******/ type = 'LINK'; 292 | /******/ } else if (/.*.js??.*/.test(err.request)) { 293 | /******/ type = 'SCRIPT'; 294 | /******/ } 295 | /******/ if (options === undefined) { 296 | /******/ options = { 297 | /******/ LINK: 0, 298 | /******/ SCRIPT: 0 299 | /******/ }; 300 | /******/ } 301 | /******/ options[type]++; 302 | /******/ // 最小值为1 303 | /******/ if (options[type] <= 2) { 304 | /******/ return newRequireEnsure(chunkId, options); 305 | /******/ } 306 | /******/ }) 307 | /******/ } 308 | /******/ // run deferred modules from other chunks 309 | /******/ checkDeferredModules(); 310 | /******/ }) 311 | /************************************************************************/ 312 | /******/ ([]); --------------------------------------------------------------------------------