diff --git a/.editorconfig b/.editorconfig index 9f89f364..aa6d2b06 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,6 @@ trim_trailing_whitespace = true [*.md] insert_final_newline = true trim_trailing_whitespace = false + +[test/cases/**] +insert_final_newline = false diff --git a/.eslintignore b/.eslintignore index 8477d2ab..9c3ba619 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,5 @@ /test/fixtures /test/cases/*/expected /test/js +/test/stress/dist +/test/stress/src/tmp diff --git a/.prettierignore b/.prettierignore index 41ff7724..750b7c06 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,4 +4,6 @@ /test/fixtures /test/cases/*/expected /test/js +/test/stress/dist +/test/stress/src/tmp CHANGELOG.md diff --git a/package.json b/package.json index 01a2cd4e..6003c725 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "test:watch": "cross-env NODE_ENV=test jest --watch", "test:coverage": "cross-env NODE_ENV=test jest --collectCoverageFrom=\"src/**/*.js\" --coverage", "test:manual": "npm run build && webpack-dev-server test/manual/src/index.js --open --config test/manual/webpack.config.js", + "test:stress": "node --max-old-space-size=8192 test/stress/build.js", "pretest": "npm run lint", "test": "cross-env NODE_ENV=test npm run test:coverage", "defaults": "webpack-defaults" diff --git a/src/index.js b/src/index.js index d9f6bf2d..490da4f9 100644 --- a/src/index.js +++ b/src/index.js @@ -24,6 +24,24 @@ const REGEXP_NAME = /\[name\]/i; const REGEXP_PLACEHOLDERS = /\[(name|id|chunkhash)\]/g; const DEFAULT_FILENAME = '[name].css'; +const EMPTY_MODULES_CLEANUP_DEP_TYPES = new Set([ + 'harmony side effect evaluation', + 'import()', + 'single entry', +]); + +class SetMap extends Map { + add(key, value) { + const set = this.get(key); + // eslint-disable-next-line no-undefined + if (set === undefined) { + super.set(key, new Set([value])); + } else { + set.add(value); + } + } +} + class CssDependencyTemplate { apply() {} } @@ -390,6 +408,51 @@ class MiniCssExtractPlugin { return source; } ); + + compilation.hooks.optimizeChunks.tap(pluginName, (chunks) => { + const toRemoveMap = new SetMap(); + + for (const chunk of chunks) { + for (const module of chunk.modulesIterable) { + if (module.type === MODULE_TYPE) { + for (const cssModuleReason of module.reasons) { + let hasUnsupportedDependency = false; + + for (const reason of cssModuleReason.module.reasons) { + if ( + EMPTY_MODULES_CLEANUP_DEP_TYPES.has(reason.dependency.type) + ) { + toRemoveMap.add( + reason.module || cssModuleReason.module, + reason.dependency + ); + } else { + hasUnsupportedDependency = true; + } + } + + if ( + !hasUnsupportedDependency && + cssModuleReason.module && + cssModuleReason.module.buildMeta.extracted + ) { + chunk.removeModule(cssModuleReason.module); + } + } + } + } + } + + for (const [module, set] of toRemoveMap) { + module.dependencies = module.dependencies.filter((d) => { + if (set.has(d)) { + d.disconnect(); + return false; + } + return true; + }); + } + }); }); } diff --git a/src/loader.js b/src/loader.js index 619c48d3..37d28197 100644 --- a/src/loader.js +++ b/src/loader.js @@ -217,6 +217,11 @@ export function pitch(request) { ? hotLoader(result, { context: this.context, options, locals }) : result; + this._module.buildMeta = { + ...this._module.buildMeta, + extracted: !locals && !options.hmr, + }; + return callback(null, resultSource); }); } diff --git a/test/cases/chunkFilename/expected/1.async.css b/test/cases/chunkFilename/expected/0.async.css similarity index 100% rename from test/cases/chunkFilename/expected/1.async.css rename to test/cases/chunkFilename/expected/0.async.css diff --git a/test/cases/filename-without-template/expected/1.main.css b/test/cases/filename-without-template/expected/0.main.css similarity index 100% rename from test/cases/filename-without-template/expected/1.main.css rename to test/cases/filename-without-template/expected/0.main.css diff --git a/test/cases/nested/expected/main.js b/test/cases/nested/expected/main.js new file mode 100644 index 00000000..844818b5 --- /dev/null +++ b/test/cases/nested/expected/main.js @@ -0,0 +1,110 @@ +/******/ (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, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _component__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); + + + + + +/***/ }), +/* 1 */, +/* 2 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/test/cases/shared-import/expected/1.css b/test/cases/shared-import/expected/0.css similarity index 100% rename from test/cases/shared-import/expected/1.css rename to test/cases/shared-import/expected/0.css diff --git a/test/cases/simple-async-source-map/expected/0.css b/test/cases/simple-async-source-map/expected/0.css new file mode 100644 index 00000000..483851fe --- /dev/null +++ b/test/cases/simple-async-source-map/expected/0.css @@ -0,0 +1,6 @@ +.async { + background: blue; +} + + +/*# sourceMappingURL=0.css.map*/ \ No newline at end of file diff --git a/test/cases/simple-async-source-map/expected/0.css.map b/test/cases/simple-async-source-map/expected/0.css.map new file mode 100644 index 00000000..ddec27ed --- /dev/null +++ b/test/cases/simple-async-source-map/expected/0.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"0.css","sourcesContent":[".async {\n background: blue;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/test/cases/simple-async-source-map/expected/1.css b/test/cases/simple-async-source-map/expected/1.css deleted file mode 100644 index 18c06fae..00000000 --- a/test/cases/simple-async-source-map/expected/1.css +++ /dev/null @@ -1,6 +0,0 @@ -.in-async { - background: green; -} - - -/*# sourceMappingURL=1.css.map*/ \ No newline at end of file diff --git a/test/cases/simple-async-source-map/expected/1.css.map b/test/cases/simple-async-source-map/expected/1.css.map deleted file mode 100644 index 80ae7050..00000000 --- a/test/cases/simple-async-source-map/expected/1.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["webpack:///./in-async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"1.css","sourcesContent":[".in-async {\n background: green;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/test/cases/simple-async-source-map/expected/2.css b/test/cases/simple-async-source-map/expected/2.css index 64cde675..cc80fa58 100644 --- a/test/cases/simple-async-source-map/expected/2.css +++ b/test/cases/simple-async-source-map/expected/2.css @@ -1,5 +1,5 @@ -.async { - background: blue; +.in-async { + background: green; } diff --git a/test/cases/simple-async-source-map/expected/2.css.map b/test/cases/simple-async-source-map/expected/2.css.map index f31c083f..806983fa 100644 --- a/test/cases/simple-async-source-map/expected/2.css.map +++ b/test/cases/simple-async-source-map/expected/2.css.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///./async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"2.css","sourcesContent":[".async {\n background: blue;\n}\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///./in-async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"2.css","sourcesContent":[".in-async {\n background: green;\n}\n"],"sourceRoot":""} \ No newline at end of file diff --git a/test/cases/simple-async/expected/0.css b/test/cases/simple-async/expected/0.css new file mode 100644 index 00000000..67332816 --- /dev/null +++ b/test/cases/simple-async/expected/0.css @@ -0,0 +1,4 @@ +.async { + background: blue; +} + diff --git a/test/cases/simple-async/expected/1.css b/test/cases/simple-async/expected/1.css deleted file mode 100644 index 9dc882a1..00000000 --- a/test/cases/simple-async/expected/1.css +++ /dev/null @@ -1,4 +0,0 @@ -.in-async { - background: green; -} - diff --git a/test/cases/simple-async/expected/2.css b/test/cases/simple-async/expected/2.css index 67332816..9dc882a1 100644 --- a/test/cases/simple-async/expected/2.css +++ b/test/cases/simple-async/expected/2.css @@ -1,4 +1,4 @@ -.async { - background: blue; +.in-async { + background: green; } diff --git a/test/cases/simple-require/expected/main.css b/test/cases/simple-require/expected/main.css new file mode 100644 index 00000000..cebc5c1c --- /dev/null +++ b/test/cases/simple-require/expected/main.css @@ -0,0 +1,4 @@ +body { + background: red; +} + diff --git a/test/cases/simple-require/expected/main.js b/test/cases/simple-require/expected/main.js new file mode 100644 index 00000000..e32a34ee --- /dev/null +++ b/test/cases/simple-require/expected/main.js @@ -0,0 +1,101 @@ +/******/ (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__) { + +__webpack_require__(1); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/test/cases/simple-require/index.js b/test/cases/simple-require/index.js new file mode 100644 index 00000000..7a44f4ff --- /dev/null +++ b/test/cases/simple-require/index.js @@ -0,0 +1 @@ +require('./style.css'); diff --git a/test/cases/simple-require/style.css b/test/cases/simple-require/style.css new file mode 100644 index 00000000..67ce83e4 --- /dev/null +++ b/test/cases/simple-require/style.css @@ -0,0 +1,3 @@ +body { + background: red; +} diff --git a/test/cases/simple-require/webpack.config.js b/test/cases/simple-require/webpack.config.js new file mode 100644 index 00000000..4e160f26 --- /dev/null +++ b/test/cases/simple-require/webpack.config.js @@ -0,0 +1,18 @@ +import Self from '../../../src'; + +module.exports = { + entry: './index.js', + module: { + rules: [ + { + test: /\.css$/, + use: [Self.loader, 'css-loader'], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/simple/expected/main.js b/test/cases/simple/expected/main.js new file mode 100644 index 00000000..04cc387b --- /dev/null +++ b/test/cases/simple/expected/main.js @@ -0,0 +1,97 @@ +/******/ (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, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); + + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/test/stress/.gitignore b/test/stress/.gitignore new file mode 100644 index 00000000..4943e34a --- /dev/null +++ b/test/stress/.gitignore @@ -0,0 +1,2 @@ +dist +src/tmp diff --git a/test/stress/build.js b/test/stress/build.js new file mode 100644 index 00000000..2ca5cbb5 --- /dev/null +++ b/test/stress/build.js @@ -0,0 +1,75 @@ +/* eslint-disable no-console */ + +const pathlib = require('path'); +const fs = require('fs'); +const crypto = require('crypto'); + +const del = require('del'); + +const webpack = require('webpack'); + +const config = require('./webpack.config'); + +const randomId = () => crypto.randomBytes(16).toString('hex'); +const createModule = (deps = []) => { + const id = randomId(); + const cssPath = pathlib.resolve(__dirname, `src/tmp/${id}.css`); + const jsPath = pathlib.resolve(__dirname, `src/tmp/${id}.js`); + const cssContent = `.c-${id} { display: block; }`; + const jsContent = [...deps.filter(Boolean), cssPath] + .map((p) => `import '${p}';`) + .join('\n'); + fs.writeFileSync(cssPath, cssContent); + fs.writeFileSync(jsPath, jsContent); + return jsPath; +}; + +const distPath = pathlib.resolve(__dirname, 'dist'); +const tmpPath = pathlib.resolve(__dirname, 'src/tmp'); + +del.sync(distPath); +del.sync(tmpPath); +fs.mkdirSync(tmpPath); + +const SIZE = 100; +const DEPTH = 80; + +console.log(`Preparing ${SIZE}x${DEPTH} data...`); + +const indexSrc = Array.from({ length: SIZE }) + .map(() => + Array.from({ length: DEPTH }).reduce((prev) => createModule([prev]), null) + ) + .map((p) => `import '${p}';`) + .join('\n'); + +fs.writeFileSync(pathlib.resolve(__dirname, `src/tmp/index.js`), indexSrc); + +console.log(`Running Webpack...`); + +webpack(config).run((err, stats) => { + if (err) { + console.error(err); + process.exit(1); + } + console.log( + stats.toString({ + all: false, + colors: true, + builtAt: true, + env: true, + hash: true, + timings: true, + version: true, + modules: true, + maxModules: 0, + errors: true, + errorDetails: true, + warnings: true, + moduleTrace: true, + assets: true, + entrypoints: true, + performance: true, + }) + ); +}); diff --git a/test/stress/src/index.js b/test/stress/src/index.js new file mode 100644 index 00000000..78984d04 --- /dev/null +++ b/test/stress/src/index.js @@ -0,0 +1 @@ +import './tmp/index.js'; // eslint-disable-line import/no-unresolved, import/extensions diff --git a/test/stress/webpack.config.js b/test/stress/webpack.config.js new file mode 100644 index 00000000..f53b7b01 --- /dev/null +++ b/test/stress/webpack.config.js @@ -0,0 +1,30 @@ +const pathlib = require('path'); + +const Self = require('../../'); + +const config = (mode) => { + return { + mode, + name: mode, + entry: pathlib.resolve(__dirname, 'src/index.js'), + output: { + filename: `${mode}.js`, + path: pathlib.resolve(__dirname, 'dist'), + }, + module: { + rules: [ + { + test: /\.css$/, + use: [Self.loader, 'css-loader'], + }, + ], + }, + plugins: [ + new Self({ + filename: `[name]-${mode}.css`, + }), + ], + }; +}; + +module.exports = [config('development'), config('production')];