From 4ed9c5a85daf11c651e3d564823dbc9d91fdc6af Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Tue, 9 Apr 2019 03:07:56 -0700 Subject: [PATCH] feat: adding hot module reloading (#334) --- .gitignore | 1 + README.md | 64 +- package-lock.json | 555 ++++++++++++------ package.json | 9 +- src/hmr/hotModuleReplacement.js | 173 ++++++ src/index.js | 3 +- src/loader.js | 35 +- test/TestCases.test.js | 21 + test/__snapshots__/TestCases.test.js.snap | 178 ++++++ test/cases/hmr/a.css | 1 + test/cases/hmr/b.css | 5 + test/cases/hmr/c.css | 5 + test/cases/hmr/expected/main.css | 14 + test/cases/hmr/expected/main.js | 96 +++ test/cases/hmr/index.css | 2 + test/cases/hmr/webpack.config.js | 26 + .../expected/style.25d094fb4a6ef6ef0222.js | 10 - ...ef5.css => style.9b11dfbd73d90b346d16.css} | 0 ...039.css => style.b62a24baf4785af5a972.css} | 0 test/cases/js-hash/webpack.config.js | 9 +- 20 files changed, 1009 insertions(+), 198 deletions(-) create mode 100644 src/hmr/hotModuleReplacement.js create mode 100644 test/__snapshots__/TestCases.test.js.snap create mode 100644 test/cases/hmr/a.css create mode 100644 test/cases/hmr/b.css create mode 100644 test/cases/hmr/c.css create mode 100644 test/cases/hmr/expected/main.css create mode 100644 test/cases/hmr/expected/main.js create mode 100644 test/cases/hmr/index.css create mode 100644 test/cases/hmr/webpack.config.js delete mode 100644 test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js rename test/cases/js-hash/expected/{style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css => style.9b11dfbd73d90b346d16.css} (100%) rename test/cases/js-hash/expected/{style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css => style.b62a24baf4785af5a972.css} (100%) diff --git a/.gitignore b/.gitignore index b70b127e..cb2a818c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ Thumbs.db .vscode *.sublime-project *.sublime-workspace +.idea diff --git a/README.md b/README.md index 72c21d77..a2022c2a 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,6 @@ Compared to the extract-text-webpack-plugin: * Easier to use * Specific to CSS -TODO: - -* HMR support

Install

@@ -69,8 +66,9 @@ module.exports = { loader: MiniCssExtractPlugin.loader, options: { // you can specify a publicPath here - // by default it use publicPath in webpackOptions.output - publicPath: '../' + // by default it uses publicPath in webpackOptions.output + publicPath: '../', + hmr: process.env.NODE_ENV === 'development' } }, "css-loader" @@ -149,7 +147,12 @@ module.exports = { { test: /\.(sa|sc|c)ss$/, use: [ - devMode ? 'style-loader' : MiniCssExtractPlugin.loader, + { + loader: MiniCssExtractPlugin.loader, + options: { + hmr: process.env.NODE_ENV === 'development' + } + }, 'css-loader', 'postcss-loader', 'sass-loader', @@ -160,6 +163,51 @@ module.exports = { } ``` +#### Hot Module Reloading (HMR) + +extract-mini-css-plugin supports hot reloading of actual css files in development. Some options are provided to enable HMR of both standard stylesheets and locally scoped CSS or CSS modules. Below is an example configuration of mini-css for HMR use with CSS modules. + + +While we attempt to hmr css-modules. It is not easy to perform when code-splitting with custom chunk names. `reloadAll` is an option that should only be enabled if HMR isn't working correctly. The core challenge with css-modules is that when code-split, the chunk ids can and do end up different compared to the filename. + + + +**webpack.config.js** + +```js +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +module.exports = { + plugins: [ + new MiniCssExtractPlugin({ + // Options similar to the same options in webpackOptions.output + // both options are optional + filename: "[name].css", + chunkFilename: "[id].css" + }) + ], + module: { + rules: [ + { + test: /\.css$/, + use: [ + { + loader: MiniCssExtractPlugin.loader, + options: { + // only enable hot in development + hmr: process.env.NODE_ENV === 'development', + // if hmr does not work, this is a forceful method. + reloadAll: true + } + }, + "css-loader" + ] + } + ] + } +} +``` + + ### Minimizing For Production While webpack 5 is likely to come with a CSS minimizer built-in, with webpack 4 you need to bring your own. To minify the output, use a plugin like [optimize-css-assets-webpack-plugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin). Setting `optimization.minimizer` overrides the defaults provided by webpack, so make sure to also specify a JS minimizer: @@ -314,6 +362,10 @@ module.exports = { For long term caching use `filename: "[contenthash].css"`. Optionally add `[name]`. +### Remove Order Warnings + +If the terminal is getting bloated with chunk order warnings. You can filter by configuring [warningsFilter](https://webpack.js.org/configuration/stats/) withing the webpack stats option + ### Media Query Plugin If you'd like to extract the media queries from the extracted CSS (so mobile users don't need to load desktop or tablet specific CSS anymore) you should use one of the following plugins: diff --git a/package-lock.json b/package-lock.json index d3a4647e..b8067258 100644 --- a/package-lock.json +++ b/package-lock.json @@ -557,6 +557,11 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=" + }, "ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -587,8 +592,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -637,6 +641,15 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1828,8 +1841,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -1939,8 +1951,7 @@ "bluebird": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", - "dev": true + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" }, "bn.js": { "version": "4.11.8", @@ -2010,7 +2021,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2182,8 +2192,7 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "buffer-indexof": { "version": "1.1.1", @@ -2404,6 +2413,24 @@ "integrity": "sha512-CAZ9QXGViBvhHnmIHhsTPSWFBujDaelKnUj7wwImbyQRxmXynYqKGi3UaZTSz9MoVh+1EVxOS/DFIkrJYgR3aw==", "dev": true }, + "caporal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/caporal/-/caporal-1.1.0.tgz", + "integrity": "sha512-R5qo2QGoqBM6RvzHonGhUuEJSeqEa4lD1r+cPUEY2+YsXhpQVTS2TvScfIbi6ydFdhzFCNeNUB1v0YrRBvsbdg==", + "requires": { + "bluebird": "^3.4.7", + "cli-table3": "^0.5.0", + "colorette": "1.0.1", + "fast-levenshtein": "^2.0.6", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.merge": "^4.6.0", + "micromist": "1.1.0", + "prettyjson": "^1.2.1", + "tabtab": "^2.2.2", + "winston": "^2.3.1" + } + }, "capture-exit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", @@ -2600,6 +2627,16 @@ } } }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, "cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -2641,8 +2678,7 @@ "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, "cliui": { "version": "4.1.0", @@ -2728,8 +2764,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "collection-visit": { "version": "1.0.0", @@ -2776,6 +2811,11 @@ "color-name": "^1.0.0" } }, + "colorette": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.0.1.tgz", + "integrity": "sha512-40MnlppkzHhFjRhtXunbpqKUT+eJn0gyVGi8aQlNSG8T2CCy31NdD7yktcS0aizH1VP2OhhQCyGMeTp0a/fvaw==" + }, "colormin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", @@ -2790,8 +2830,7 @@ "colors": { "version": "1.1.2", "resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" }, "combined-stream": { "version": "1.0.7", @@ -2866,14 +2905,12 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -3461,8 +3498,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { "version": "4.0.0", @@ -3710,6 +3746,11 @@ "array-find-index": "^1.0.1" } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -3780,7 +3821,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -4164,6 +4204,11 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -4510,6 +4555,23 @@ "is-regex": "^1.0.4" } }, + "es-check": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es-check/-/es-check-5.0.0.tgz", + "integrity": "sha512-30n+EZt5KjazXEvyYr2DXJCOJJWfdT1unRp5+Szlcja6uGAB3Sh3QPjRsxd2xgN9SFj4S5P8pdBISwGcDdS45Q==", + "requires": { + "acorn": "6.0.4", + "caporal": "1.1.0", + "glob": "^7.1.2" + }, + "dependencies": { + "acorn": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", + "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==" + } + } + }, "es-to-primitive": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", @@ -4530,8 +4592,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.11.0", @@ -4935,8 +4996,7 @@ "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" }, "expand-brackets": { "version": "0.1.5", @@ -5028,8 +5088,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -5078,6 +5137,11 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -5423,8 +5487,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fastparse": { "version": "1.1.2", @@ -5788,15 +5851,13 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", "dev": true, - "optional": true, "requires": { "nan": "^2.9.2", "node-pre-gyp": "^0.10.0" @@ -5805,8 +5866,7 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ansi-regex": { "version": "2.1.1", @@ -5816,14 +5876,12 @@ "aproba": { "version": "1.2.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, "dev": true, - "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -5846,8 +5904,7 @@ "chownr": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "code-point-at": { "version": "1.1.0", @@ -5867,14 +5924,12 @@ "core-util-is": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "debug": { "version": "2.6.9", "bundled": true, "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -5882,26 +5937,22 @@ "deep-extend": { "version": "0.5.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "delegates": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, "dev": true, - "optional": true, "requires": { "minipass": "^2.2.1" } @@ -5909,14 +5960,12 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "gauge": { "version": "2.7.4", "bundled": true, "dev": true, - "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -5932,7 +5981,6 @@ "version": "7.1.2", "bundled": true, "dev": true, - "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5945,14 +5993,12 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "iconv-lite": { "version": "0.4.21", "bundled": true, "dev": true, - "optional": true, "requires": { "safer-buffer": "^2.1.0" } @@ -5961,7 +6007,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimatch": "^3.0.4" } @@ -5970,7 +6015,6 @@ "version": "1.0.6", "bundled": true, "dev": true, - "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5984,8 +6028,7 @@ "ini": { "version": "1.3.5", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -5998,8 +6041,7 @@ "isarray": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minimatch": { "version": "3.0.4", @@ -6027,7 +6069,6 @@ "version": "1.1.0", "bundled": true, "dev": true, - "optional": true, "requires": { "minipass": "^2.2.1" } @@ -6043,14 +6084,12 @@ "ms": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "needle": { "version": "2.2.0", "bundled": true, "dev": true, - "optional": true, "requires": { "debug": "^2.1.2", "iconv-lite": "^0.4.4", @@ -6061,7 +6100,6 @@ "version": "0.10.0", "bundled": true, "dev": true, - "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -6079,7 +6117,6 @@ "version": "4.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -6088,14 +6125,12 @@ "npm-bundled": { "version": "1.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "npm-packlist": { "version": "1.1.10", "bundled": true, "dev": true, - "optional": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -6105,7 +6140,6 @@ "version": "4.1.2", "bundled": true, "dev": true, - "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -6121,8 +6155,7 @@ "object-assign": { "version": "4.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "once": { "version": "1.4.0", @@ -6135,20 +6168,17 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "osenv": { "version": "0.1.5", "bundled": true, "dev": true, - "optional": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -6157,20 +6187,17 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "rc": { "version": "1.2.7", "bundled": true, "dev": true, - "optional": true, "requires": { "deep-extend": "^0.5.1", "ini": "~1.3.0", @@ -6181,8 +6208,7 @@ "minimist": { "version": "1.2.0", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -6190,7 +6216,6 @@ "version": "2.3.6", "bundled": true, "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6205,7 +6230,6 @@ "version": "2.6.2", "bundled": true, "dev": true, - "optional": true, "requires": { "glob": "^7.0.5" } @@ -6218,32 +6242,27 @@ "safer-buffer": { "version": "2.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "sax": { "version": "1.2.4", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "semver": { "version": "5.5.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "string-width": { "version": "1.0.2", @@ -6259,7 +6278,6 @@ "version": "1.1.1", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -6275,14 +6293,12 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "tar": { "version": "4.4.1", "bundled": true, "dev": true, - "optional": true, "requires": { "chownr": "^1.0.1", "fs-minipass": "^1.2.5", @@ -6296,14 +6312,12 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "wide-align": { "version": "1.1.2", "bundled": true, "dev": true, - "optional": true, "requires": { "string-width": "^1.0.2" } @@ -6332,6 +6346,18 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -6636,7 +6662,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6848,7 +6873,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6886,6 +6910,11 @@ "has-symbol-support-x": "^1.4.1" } }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -7536,7 +7565,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -7545,8 +7573,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -7791,8 +7818,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-generator-fn": { "version": "1.0.0", @@ -7917,8 +7943,7 @@ "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, "is-redirect": { "version": "1.0.0", @@ -8028,8 +8053,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isbinaryfile": { "version": "3.0.3", @@ -8058,8 +8082,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-api": { "version": "1.3.7", @@ -9259,8 +9282,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -9271,8 +9293,7 @@ "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, "lodash.debounce": { "version": "4.0.8", @@ -9280,11 +9301,15 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, "lodash.kebabcase": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", - "dev": true + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=" }, "lodash.memoize": { "version": "4.1.2", @@ -9295,8 +9320,7 @@ "lodash.merge": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" }, "lodash.mergewith": { "version": "4.6.1", @@ -9310,6 +9334,21 @@ "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=", "dev": true }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=" + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=" + }, "lodash.pick": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", @@ -9362,8 +9401,7 @@ "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "lodash.upperfirst": { "version": "4.3.1", @@ -9709,6 +9747,14 @@ "regex-cache": "^0.4.2" } }, + "micromist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromist/-/micromist-1.1.0.tgz", + "integrity": "sha512-+CQ76pabE9egniSEdmDuH+j2cYyIBKP97kujG8ZLZyLCRq5ExwtIy4DPHPFrq4jVbhMRBnyjuH50KU9Ohs8QCg==", + "requires": { + "lodash.camelcase": "^4.3.0" + } + }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -9768,7 +9814,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -9776,8 +9821,7 @@ "minimist": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "minimist-options": { "version": "3.0.2", @@ -9832,7 +9876,6 @@ "version": "0.5.1", "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -9840,8 +9883,7 @@ "minimist": { "version": "0.0.8", "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, @@ -9900,8 +9942,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multicast-dns": { "version": "6.2.3", @@ -9941,8 +9982,7 @@ "version": "2.11.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", - "dev": true, - "optional": true + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -10179,6 +10219,16 @@ "which": "^1.2.10" } }, + "npmlog": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + } + }, "null-check": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", @@ -10194,8 +10244,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { "version": "2.0.9", @@ -10212,8 +10261,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -10322,7 +10370,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -10484,14 +10531,12 @@ "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", - "dev": true + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=" }, "os-tmpdir": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "output-file-sync": { "version": "1.1.2", @@ -10733,8 +10778,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -10797,14 +10841,12 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -11449,6 +11491,15 @@ } } }, + "prettyjson": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", + "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=", + "requires": { + "colors": "^1.1.2", + "minimist": "^1.2.0" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -11464,8 +11515,7 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "progress": { "version": "2.0.3", @@ -11734,7 +11784,6 @@ "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12476,7 +12525,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, "requires": { "is-promise": "^2.1.0" } @@ -12490,6 +12538,11 @@ "aproba": "^1.1.1" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, "rx-lite": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", @@ -12525,8 +12578,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -13306,7 +13358,6 @@ "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", - "dev": true, "requires": { "concat-stream": "^1.4.7", "os-shim": "^0.1.2" @@ -13438,6 +13489,11 @@ "figgy-pudding": "^3.5.1" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "stack-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", @@ -13747,7 +13803,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -13756,14 +13811,12 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -13774,7 +13827,6 @@ "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -13794,7 +13846,6 @@ "version": "3.0.1", "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -13944,6 +13995,143 @@ } } }, + "tabtab": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz", + "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=", + "requires": { + "debug": "^2.2.0", + "inquirer": "^1.0.2", + "lodash.difference": "^4.5.0", + "lodash.uniq": "^4.5.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "npmlog": "^2.0.3", + "object-assign": "^4.1.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "external-editor": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", + "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "requires": { + "extend": "^3.0.0", + "spawn-sync": "^1.0.15", + "tmp": "^0.0.29" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "inquirer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", + "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "external-editor": "^1.1.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "mute-stream": "0.0.6", + "pinkie-promise": "^2.0.0", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "mute-stream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", + "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=" + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tmp": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, "tapable": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", @@ -14152,8 +14340,7 @@ "through": { "version": "2.3.8", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.5", @@ -14341,8 +14528,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uglify-js": { "version": "3.4.9", @@ -14628,8 +14814,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.0", @@ -16563,6 +16748,31 @@ "string-width": "^2.1.1" } }, + "winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + } + } + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -16613,8 +16823,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", diff --git a/package.json b/package.json index 0d4f3dac..508f91a5 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,9 @@ "webpack": "^4.4.0" }, "dependencies": { - "schema-utils": "^1.0.0", "loader-utils": "^1.1.0", + "normalize-url": "^2.0.1", + "schema-utils": "^1.0.0", "webpack-sources": "^1.1.0" }, "devDependencies": { @@ -61,9 +62,11 @@ "css-loader": "^0.28.10", "del": "^3.0.0", "del-cli": "^1.1.0", + "es-check": "^5.0.0", "eslint": "^4.17.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-prettier": "^2.6.0", + "execa": "^1.0.0", "file-loader": "^1.1.11", "husky": "^0.14.3", "jest": "^22.2.2", @@ -72,10 +75,10 @@ "pre-commit": "^1.2.2", "prettier": "^1.11.1", "standard-version": "^4.3.0", - "webpack": "^4.14.0", + "webpack": "4.28.0", "webpack-cli": "^2.0.13", "webpack-defaults": "^2.3.0", - "webpack-dev-server": "^3.1.1" + "webpack-dev-server": "^3.1.14" }, "keywords": [ "webpack" diff --git a/src/hmr/hotModuleReplacement.js b/src/hmr/hotModuleReplacement.js new file mode 100644 index 00000000..62f08f79 --- /dev/null +++ b/src/hmr/hotModuleReplacement.js @@ -0,0 +1,173 @@ +/* global document, window */ +/* eslint func-names: 0 */ +/* eslint no-var: 0 */ +/* eslint vars-on-top: 0 */ +/* eslint prefer-arrow-func: 0 */ +/* eslint prefer-rest-params: 0 */ +/* eslint prefer-arrow-callback: 0 */ +/* eslint prefer-template: 0 */ + +var normalizeUrl = require('normalize-url'); + +var srcByModuleId = Object.create(null); + +var noDocument = typeof document === 'undefined'; + +var forEach = Array.prototype.forEach; + +function debounce(fn, time) { + var timeout = 0; + + // eslint-disable-next-line func-names + return function() { + var self = this; + var args = arguments; + + // eslint-disable-next-line prefer-rest-params + var functionCall = function functionCall() { + return fn.apply(self, args); + }; + + clearTimeout(timeout); + timeout = setTimeout(functionCall, time); + }; +} + +function noop() {} + +function getCurrentScriptUrl(moduleId) { + var src = srcByModuleId[moduleId]; + + if (!src) { + if (document.currentScript) { + src = document.currentScript.src; + } else { + var scripts = document.getElementsByTagName('script'); + var lastScriptTag = scripts[scripts.length - 1]; + + if (lastScriptTag) { + src = lastScriptTag.src; + } + } + srcByModuleId[moduleId] = src; + } + + return function(fileMap) { + if (!src) { + return null; + } + var splitResult = src.split(/([^\\/]+)\.js$/); + var filename = splitResult && splitResult[1]; + if (!filename) { + return [src.replace('.js', '.css')]; + } + if (!fileMap) { + return [src.replace('.js', '.css')]; + } + return fileMap.split(',').map(function(mapRule) { + var reg = new RegExp(filename + '\\.js$', 'g'); + return normalizeUrl( + src.replace(reg, mapRule.replace(/{fileName}/g, filename) + '.css'), + { stripWWW: false } + ); + }); + }; +} + +function updateCss(el, url) { + if (!url) { + url = el.href.split('?')[0]; + } + if (el.isLoaded === false) { + // We seem to be about to replace a css link that hasn't loaded yet. + // We're probably changing the same file more than once. + return; + } + if (!url || !(url.indexOf('.css') > -1)) return; + + el.visited = true; + var newEl = el.cloneNode(); // eslint-disable-line vars-on-top + + newEl.isLoaded = false; + + newEl.addEventListener('load', function() { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); + + newEl.addEventListener('error', function() { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); + + newEl.href = url + '?' + Date.now(); + el.parentNode.appendChild(newEl); +} + +function getReloadUrl(href, src) { + var ret; + href = normalizeUrl(href, { stripWWW: false }); + // eslint-disable-next-line array-callback-return + src.some(function(url) { + if (href.indexOf(src) > -1) { + ret = url; + } + }); + return ret; +} + +function reloadStyle(src) { + var elements = document.querySelectorAll('link'); + var loaded = false; + + forEach.call(elements, function(el) { + var url = getReloadUrl(el.href, src); + + if (el.visited === true) return; + + if (url) { + updateCss(el, url); + loaded = true; + } + }); + + return loaded; +} + +function reloadAll() { + var elements = document.querySelectorAll('link'); + forEach.call(elements, function(el) { + if (el.visited === true) return; + updateCss(el); + }); +} + +module.exports = function(moduleId, options) { + if (noDocument) { + console.log('no window.document found, will not HMR CSS'); + return noop; + } + + // eslint-disable-next-line vars-on-top + var getScriptSrc = getCurrentScriptUrl(moduleId); + + function update() { + var src = getScriptSrc(options.filename); + var reloaded = reloadStyle(src); + + if (options.locals) { + console.log('[HMR] Detected local css modules. Reload all css'); + reloadAll(); + return; + } + + if (reloaded && !options.reloadAll) { + console.log('[HMR] css reload %s', src.join(' ')); + } else { + console.log('[HMR] Reload all css'); + reloadAll(); + } + } + + return debounce(update, 50); +}; diff --git a/src/index.js b/src/index.js index c905bb82..93760d87 100644 --- a/src/index.js +++ b/src/index.js @@ -116,6 +116,7 @@ class MiniCssExtractPlugin { }, options ); + if (!this.options.chunkFilename) { const { filename } = this.options; const hasName = filename.includes('[name]'); @@ -482,7 +483,7 @@ class MiniCssExtractPlugin { const fallbackModule = bestMatch.pop(); compilation.warnings.push( new Error( - `chunk ${chunk.name || chunk.id} [mini-css-extract-plugin]\n` + + `chunk ${chunk.name || chunk.id} [${pluginName}]\n` + 'Conflicting order between:\n' + ` * ${fallbackModule.readableIdentifier(requestShortener)}\n` + `${bestMatchDeps diff --git a/src/loader.js b/src/loader.js index 5eafa7ab..5ffb50a0 100644 --- a/src/loader.js +++ b/src/loader.js @@ -1,5 +1,7 @@ import NativeModule from 'module'; +import path from 'path'; + import loaderUtils from 'loader-utils'; import NodeTemplatePlugin from 'webpack/lib/node/NodeTemplatePlugin'; import NodeTargetPlugin from 'webpack/lib/node/NodeTargetPlugin'; @@ -13,6 +15,27 @@ import schema from './options.json'; const MODULE_TYPE = 'css/mini-extract'; const pluginName = 'mini-css-extract-plugin'; +function hotLoader(content, context) { + const accept = context.locals + ? '' + : 'module.hot.accept(undefined, cssReload);'; + const result = `${content} + if(module.hot) { + // ${Date.now()} + var cssReload = require(${loaderUtils.stringifyRequest( + context.context, + path.join(__dirname, 'hmr/hotModuleReplacement.js') + )})(module.id, ${JSON.stringify({ + ...context.query, + locals: !!context.locals, + })}); + module.hot.dispose(cssReload); + ${accept} + } + `; + return result; +} + const exec = (loaderContext, code, filename) => { const module = new NativeModule(filename, loaderContext); module.paths = NativeModule._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle @@ -126,6 +149,7 @@ export function pitch(request) { } else { text = text.map((line) => { const module = findModuleById(compilation.modules, line[0]); + return { identifier: module.identifier(), content: line[1], @@ -139,11 +163,16 @@ export function pitch(request) { return callback(e); } let resultSource = `// extracted by ${pluginName}`; - if (locals && typeof resultSource !== 'undefined') { - resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`; - } + const result = locals + ? `\nmodule.exports = ${JSON.stringify(locals)};` + : ''; + + resultSource += query.hmr + ? hotLoader(result, { context: this.context, query, locals }) + : result; return callback(null, resultSource); }); } + export default function() {} diff --git a/test/TestCases.test.js b/test/TestCases.test.js index 10a49bf0..c0cb3a39 100644 --- a/test/TestCases.test.js +++ b/test/TestCases.test.js @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import webpack from 'webpack'; +import execa from 'execa'; describe('TestCases', () => { const casesDirectory = path.resolve(__dirname, 'cases'); @@ -92,3 +93,23 @@ describe('TestCases', () => { } } }); + +describe('HMR', () => { + it('matches snapshot', () => { + const hmr = fs + .readFileSync(path.join(__dirname, '../src/hmr/hotModuleReplacement.js')) + .toString(); + + expect(hmr).toMatchSnapshot(); + }); + + it('is es5 only', () => { + const { stderr } = execa.shellSync( + 'npx es-check es5 src/hmr/hotModuleReplacement.js' + ); + + expect( + stderr.indexOf('there were no ES version matching errors') > -1 + ).toBe(true); + }); +}); diff --git a/test/__snapshots__/TestCases.test.js.snap b/test/__snapshots__/TestCases.test.js.snap new file mode 100644 index 00000000..b6f3c48b --- /dev/null +++ b/test/__snapshots__/TestCases.test.js.snap @@ -0,0 +1,178 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`HMR matches snapshot 1`] = ` +"/* global document, window */ +/* eslint func-names: 0 */ +/* eslint no-var: 0 */ +/* eslint vars-on-top: 0 */ +/* eslint prefer-arrow-func: 0 */ +/* eslint prefer-rest-params: 0 */ +/* eslint prefer-arrow-callback: 0 */ +/* eslint prefer-template: 0 */ + +var normalizeUrl = require('normalize-url'); + +var srcByModuleId = Object.create(null); + +var noDocument = typeof document === 'undefined'; + +var forEach = Array.prototype.forEach; + +function debounce(fn, time) { + var timeout = 0; + + // eslint-disable-next-line func-names + return function() { + var self = this; + var args = arguments; + + // eslint-disable-next-line prefer-rest-params + var functionCall = function functionCall() { + return fn.apply(self, args); + }; + + clearTimeout(timeout); + timeout = setTimeout(functionCall, time); + }; +} + +function noop() {} + +function getCurrentScriptUrl(moduleId) { + var src = srcByModuleId[moduleId]; + + if (!src) { + if (document.currentScript) { + src = document.currentScript.src; + } else { + var scripts = document.getElementsByTagName('script'); + var lastScriptTag = scripts[scripts.length - 1]; + + if (lastScriptTag) { + src = lastScriptTag.src; + } + } + srcByModuleId[moduleId] = src; + } + + return function(fileMap) { + if (!src) { + return null; + } + var splitResult = src.split(/([^\\\\\\\\/]+)\\\\.js$/); + var filename = splitResult && splitResult[1]; + if (!filename) { + return [src.replace('.js', '.css')]; + } + if (!fileMap) { + return [src.replace('.js', '.css')]; + } + return fileMap.split(',').map(function(mapRule) { + var reg = new RegExp(filename + '\\\\\\\\.js$', 'g'); + return normalizeUrl( + src.replace(reg, mapRule.replace(/{fileName}/g, filename) + '.css'), + { stripWWW: false } + ); + }); + }; +} + +function updateCss(el, url) { + if (!url) { + url = el.href.split('?')[0]; + } + if (el.isLoaded === false) { + // We seem to be about to replace a css link that hasn't loaded yet. + // We're probably changing the same file more than once. + return; + } + if (!url || !(url.indexOf('.css') > -1)) return; + + el.visited = true; + var newEl = el.cloneNode(); // eslint-disable-line vars-on-top + + newEl.isLoaded = false; + + newEl.addEventListener('load', function() { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); + + newEl.addEventListener('error', function() { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); + + newEl.href = url + '?' + Date.now(); + el.parentNode.appendChild(newEl); +} + +function getReloadUrl(href, src) { + var ret; + href = normalizeUrl(href, { stripWWW: false }); + // eslint-disable-next-line array-callback-return + src.some(function(url) { + if (href.indexOf(src) > -1) { + ret = url; + } + }); + return ret; +} + +function reloadStyle(src) { + var elements = document.querySelectorAll('link'); + var loaded = false; + + forEach.call(elements, function(el) { + var url = getReloadUrl(el.href, src); + + if (el.visited === true) return; + + if (url) { + updateCss(el, url); + loaded = true; + } + }); + + return loaded; +} + +function reloadAll() { + var elements = document.querySelectorAll('link'); + forEach.call(elements, function(el) { + if (el.visited === true) return; + updateCss(el); + }); +} + +module.exports = function(moduleId, options) { + if (noDocument) { + console.log('no window.document found, will not HMR CSS'); + return noop; + } + + // eslint-disable-next-line vars-on-top + var getScriptSrc = getCurrentScriptUrl(moduleId); + + function update() { + var src = getScriptSrc(options.filename); + var reloaded = reloadStyle(src); + + if (options.locals) { + console.log('[HMR] Detected local css modules. Reload all css'); + reloadAll(); + return; + } + + if (reloaded && !options.reloadAll) { + console.log('[HMR] css reload %s', src.join(' ')); + } else { + console.log('[HMR] Reload all css'); + reloadAll(); + } + } + + return debounce(update, 50); +}; +" +`; diff --git a/test/cases/hmr/a.css b/test/cases/hmr/a.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/hmr/a.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/hmr/b.css b/test/cases/hmr/b.css new file mode 100644 index 00000000..11559583 --- /dev/null +++ b/test/cases/hmr/b.css @@ -0,0 +1,5 @@ +.b { background: red; } + +@import url("https://some/external/css"); + +.b { color: yellow; } diff --git a/test/cases/hmr/c.css b/test/cases/hmr/c.css new file mode 100644 index 00000000..9c41dd1f --- /dev/null +++ b/test/cases/hmr/c.css @@ -0,0 +1,5 @@ +.c { background: red; } +@import './a.css'; +@import url("https://some/other/external/css"); + +.c { color: yellow; } diff --git a/test/cases/hmr/expected/main.css b/test/cases/hmr/expected/main.css new file mode 100644 index 00000000..cd5dacee --- /dev/null +++ b/test/cases/hmr/expected/main.css @@ -0,0 +1,14 @@ +@import url(https://some/other/external/css); +@import url(https://some/external/css); +body { background: red; } + +.c { background: red; } + +.c { color: yellow; } + +.b { background: red; } + +.b { color: yellow; } + + + diff --git a/test/cases/hmr/expected/main.js b/test/cases/hmr/expected/main.js new file mode 100644 index 00000000..0b125150 --- /dev/null +++ b/test/cases/hmr/expected/main.js @@ -0,0 +1,96 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin + if(false) { var cssReload; } + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/test/cases/hmr/index.css b/test/cases/hmr/index.css new file mode 100644 index 00000000..c03e069d --- /dev/null +++ b/test/cases/hmr/index.css @@ -0,0 +1,2 @@ +@import './c.css'; +@import './b.css'; diff --git a/test/cases/hmr/webpack.config.js b/test/cases/hmr/webpack.config.js new file mode 100644 index 00000000..078b7182 --- /dev/null +++ b/test/cases/hmr/webpack.config.js @@ -0,0 +1,26 @@ +const Self = require('../../../'); + +module.exports = { + entry: './index.css', + module: { + rules: [ + { + test: /\.css$/, + use: [ + { + loader: Self.loader, + options: { + hmr: true, + }, + }, + 'css-loader', + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js b/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js deleted file mode 100644 index 21f472ef..00000000 --- a/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js +++ /dev/null @@ -1,10 +0,0 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[ -/* 0 */, -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -// extracted by mini-css-extract-plugin -module.exports = {"a":"wX52cuPepLZcpDx5S3yYO"}; - -/***/ }) -]]); \ No newline at end of file diff --git a/test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css b/test/cases/js-hash/expected/style.9b11dfbd73d90b346d16.css similarity index 100% rename from test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css rename to test/cases/js-hash/expected/style.9b11dfbd73d90b346d16.css diff --git a/test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css b/test/cases/js-hash/expected/style.b62a24baf4785af5a972.css similarity index 100% rename from test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css rename to test/cases/js-hash/expected/style.b62a24baf4785af5a972.css diff --git a/test/cases/js-hash/webpack.config.js b/test/cases/js-hash/webpack.config.js index de241c13..e9219928 100644 --- a/test/cases/js-hash/webpack.config.js +++ b/test/cases/js-hash/webpack.config.js @@ -7,7 +7,12 @@ module.exports = [1, 2].map(n => ({ { test: /\.css$/, use: [ - Self.loader, + { + loader: Self.loader, + options:{ + hmr: false + } + }, { loader: 'css-loader', options: { @@ -30,7 +35,7 @@ module.exports = [1, 2].map(n => ({ }, plugins: [ new Self({ - filename: `[name].[contenthash].[chunkhash].css`, + filename: `[name].[chunkhash].css`, }), ], }));