Move from webpack to esbuild bundler
This commit is contained in:
parent
0aaccb9ea1
commit
1c30b49d3d
10 changed files with 156 additions and 211 deletions
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"presets": [
|
|
||||||
["@babel/env", {
|
|
||||||
"targets": {
|
|
||||||
"chrome": "57",
|
|
||||||
"firefox": "52",
|
|
||||||
"safari": "10.3",
|
|
||||||
"edge": "16",
|
|
||||||
"opera": "44"
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"@babel/preset-react"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"extends": ["eslint:recommended", "standard", "standard-jsx", "react-app"],
|
"extends": ["eslint:recommended", "standard", "standard-jsx", "react-app"],
|
||||||
"parser": "@babel/eslint-parser",
|
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": "7",
|
"ecmaVersion": "7",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
|
|
|
||||||
4
Makefile
4
Makefile
|
|
@ -81,8 +81,8 @@ $(SPEC): packaging/$(SPEC).in $(NODE_MODULES_TEST)
|
||||||
provides=$$(npm ls --omit dev --package-lock-only --depth=Infinity | grep -Eo '[^[:space:]]+@[^[:space:]]+' | sort -u | sed 's/^/Provides: bundled(npm(/; s/\(.*\)@/\1)) = /'); \
|
provides=$$(npm ls --omit dev --package-lock-only --depth=Infinity | grep -Eo '[^[:space:]]+@[^[:space:]]+' | sort -u | sed 's/^/Provides: bundled(npm(/; s/\(.*\)@/\1)) = /'); \
|
||||||
awk -v p="$$provides" '{gsub(/%{VERSION}/, "$(VERSION)"); gsub(/%{NPM_PROVIDES}/, p)}1' $< > $@
|
awk -v p="$$provides" '{gsub(/%{VERSION}/, "$(VERSION)"); gsub(/%{NPM_PROVIDES}/, p)}1' $< > $@
|
||||||
|
|
||||||
$(DIST_TEST): $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) $(shell find src/ -type f) package.json webpack.config.js
|
$(DIST_TEST): $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) $(shell find src/ -type f) package.json build.js
|
||||||
NODE_ENV=$(NODE_ENV) node_modules/.bin/webpack
|
NODE_ENV=$(NODE_ENV) ./build.js
|
||||||
|
|
||||||
watch:
|
watch:
|
||||||
NODE_ENV=$(NODE_ENV) npm run watch
|
NODE_ENV=$(NODE_ENV) npm run watch
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ After changing the code and running `make` again, reload the Cockpit page in
|
||||||
your browser.
|
your browser.
|
||||||
|
|
||||||
You can also use
|
You can also use
|
||||||
[watch mode](https://webpack.js.org/guides/development/#using-watch-mode) to
|
[watch mode](https://esbuild.github.io/api/#watch) to
|
||||||
automatically update the bundle on every code change with
|
automatically update the bundle on every code change with
|
||||||
|
|
||||||
$ npm run watch
|
$ npm run watch
|
||||||
|
|
@ -106,11 +106,11 @@ Violations of some rules can be fixed automatically by:
|
||||||
|
|
||||||
Rules configuration can be found in the `.stylelintrc.json` file.
|
Rules configuration can be found in the `.stylelintrc.json` file.
|
||||||
|
|
||||||
During fast iterative development, you can also choose to not run stylelint.
|
During fast iterative development, you can also choose to not run eslint/stylelint.
|
||||||
This speeds up the build and avoids build failures due to e. g. ill-formatted
|
This speeds up the build and avoids build failures due to e. g. ill-formatted
|
||||||
css or other issues:
|
css or other issues:
|
||||||
|
|
||||||
$ make STYLELINT=0
|
$ make LINT=0
|
||||||
|
|
||||||
# Running tests locally
|
# Running tests locally
|
||||||
|
|
||||||
|
|
|
||||||
136
build.js
Executable file
136
build.js
Executable file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import os from 'node:os';
|
||||||
|
|
||||||
|
import copy from 'esbuild-plugin-copy';
|
||||||
|
|
||||||
|
import { cleanPlugin } from './pkg/lib/esbuild-cleanup-plugin.js';
|
||||||
|
import { cockpitCompressPlugin } from './pkg/lib/esbuild-compress-plugin.js';
|
||||||
|
import { cockpitPoEsbuildPlugin } from './pkg/lib/cockpit-po-plugin.js';
|
||||||
|
import { cockpitRsyncEsbuildPlugin } from './pkg/lib/cockpit-rsync-plugin.js';
|
||||||
|
import { esbuildStylesPlugins } from './pkg/lib/esbuild-common.js';
|
||||||
|
import { eslintPlugin } from './pkg/lib/esbuild-eslint-plugin.js';
|
||||||
|
import { stylelintPlugin } from './pkg/lib/esbuild-stylelint-plugin.js';
|
||||||
|
|
||||||
|
const useWasm = os.arch() !== 'x64';
|
||||||
|
const esbuild = (await import(useWasm ? 'esbuild-wasm' : 'esbuild')).default;
|
||||||
|
|
||||||
|
const production = process.env.NODE_ENV === 'production';
|
||||||
|
const watchMode = process.env.ESBUILD_WATCH === "true";
|
||||||
|
// linters dominate the build time, so disable them for production builds by default, but enable in watch mode
|
||||||
|
const lint = process.env.LINT ? (process.env.LINT !== 0) : (watchMode || !production);
|
||||||
|
// List of directories to use when using import statements
|
||||||
|
const nodePaths = ['pkg/lib'];
|
||||||
|
const outdir = 'dist';
|
||||||
|
|
||||||
|
// Obtain package name from package.json
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync('package.json'));
|
||||||
|
|
||||||
|
function notifyEndPlugin() {
|
||||||
|
return {
|
||||||
|
name: 'notify-end',
|
||||||
|
setup(build) {
|
||||||
|
let startTime;
|
||||||
|
|
||||||
|
build.onStart(() => {
|
||||||
|
startTime = new Date();
|
||||||
|
});
|
||||||
|
|
||||||
|
build.onEnd(() => {
|
||||||
|
const endTime = new Date();
|
||||||
|
const timeStamp = endTime.toTimeString().split(' ')[0];
|
||||||
|
console.log(`${timeStamp}: Build finished in ${endTime - startTime} ms`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const cwd = process.cwd();
|
||||||
|
|
||||||
|
// similar to fs.watch(), but recursively watches all subdirectories
|
||||||
|
function watch_dirs(dir, on_change) {
|
||||||
|
const callback = (ev, dir, fname) => {
|
||||||
|
// only listen for "change" events, as renames are noisy
|
||||||
|
// ignore hidden files
|
||||||
|
const isHidden = /^\./.test(fname);
|
||||||
|
if (ev !== "change" || isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
on_change(path.join(dir, fname));
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.watch(dir, {}, (ev, path) => callback(ev, dir, path));
|
||||||
|
|
||||||
|
// watch all subdirectories in dir
|
||||||
|
const d = fs.opendirSync(dir);
|
||||||
|
let dirent;
|
||||||
|
|
||||||
|
while ((dirent = d.readSync()) !== null) {
|
||||||
|
if (dirent.isDirectory())
|
||||||
|
watch_dirs(path.join(dir, dirent.name), on_change);
|
||||||
|
}
|
||||||
|
d.closeSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = await esbuild.context({
|
||||||
|
...!production ? { sourcemap: "linked" } : {},
|
||||||
|
bundle: true,
|
||||||
|
entryPoints: ['./src/index.js'],
|
||||||
|
external: ['*.woff', '*.woff2', '*.jpg', '*.svg', '../../assets*'], // Allow external font files which live in ../../static/fonts
|
||||||
|
legalComments: 'external', // Move all legal comments to a .LEGAL.txt file
|
||||||
|
loader: { ".js": "jsx" },
|
||||||
|
minify: production,
|
||||||
|
nodePaths,
|
||||||
|
outdir,
|
||||||
|
target: ['es2020'],
|
||||||
|
plugins: [
|
||||||
|
cleanPlugin(),
|
||||||
|
...lint
|
||||||
|
? [
|
||||||
|
stylelintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(css?|scss?)$') }),
|
||||||
|
eslintPlugin({ filter: new RegExp(cwd + '\/src\/.*\.(jsx?|js?)$') })
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
// Esbuild will only copy assets that are explicitly imported and used
|
||||||
|
// in the code. This is a problem for index.html and manifest.json which are not imported
|
||||||
|
copy({
|
||||||
|
assets: [
|
||||||
|
{ from: ['./src/manifest.json'], to: ['./manifest.json'] },
|
||||||
|
{ from: ['./src/index.html'], to: ['./index.html'] },
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
...esbuildStylesPlugins,
|
||||||
|
cockpitPoEsbuildPlugin(),
|
||||||
|
...production ? [cockpitCompressPlugin()] : [],
|
||||||
|
cockpitRsyncEsbuildPlugin({ dest: packageJson.name }),
|
||||||
|
notifyEndPlugin(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await context.rebuild();
|
||||||
|
} catch (e) {
|
||||||
|
if (!watchMode)
|
||||||
|
process.exit(1);
|
||||||
|
// ignore errors in watch mode
|
||||||
|
}
|
||||||
|
|
||||||
|
if (watchMode) {
|
||||||
|
const on_change = async path => {
|
||||||
|
console.log("change detected:", path);
|
||||||
|
await context.cancel();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await context.rebuild();
|
||||||
|
} catch (e) {} // ignore in watch mode
|
||||||
|
};
|
||||||
|
|
||||||
|
watch_dirs('src', on_change);
|
||||||
|
|
||||||
|
// wait forever until Control-C
|
||||||
|
await new Promise(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
context.dispose();
|
||||||
29
package.json
29
package.json
|
|
@ -7,25 +7,21 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "LGPL-2.1",
|
"license": "LGPL-2.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch": "webpack --watch --progress",
|
"watch": "ESBUILD_WATCH='true' ./build.js",
|
||||||
"build": "webpack",
|
"build": "./build.js",
|
||||||
"eslint": "eslint --ext .js --ext .jsx src/",
|
"eslint": "eslint --ext .js --ext .jsx src/",
|
||||||
"eslint:fix": "eslint --fix --ext .js --ext .jsx src/",
|
"eslint:fix": "eslint --fix --ext .js --ext .jsx src/",
|
||||||
"stylelint": "stylelint src/*{.css,scss}",
|
"stylelint": "stylelint src/*{.css,scss}",
|
||||||
"stylelint:fix": "stylelint --fix src/*{.css,scss}"
|
"stylelint:fix": "stylelint --fix src/*{.css,scss}"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.5.4",
|
|
||||||
"@babel/eslint-parser": "^7.17.0",
|
|
||||||
"@babel/preset-env": "^7.5.4",
|
|
||||||
"@babel/preset-react": "^7.0.0",
|
|
||||||
"argparse": "^2.0.1",
|
"argparse": "^2.0.1",
|
||||||
"babel-loader": "^8.0.6",
|
|
||||||
"chrome-remote-interface": "^0.32.1",
|
"chrome-remote-interface": "^0.32.1",
|
||||||
"compression-webpack-plugin": "^9.0.0",
|
"esbuild": "^0.17.15",
|
||||||
"copy-webpack-plugin": "^9.0.0",
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"css-loader": "^6.5.0",
|
"esbuild-plugin-replace": "^1.3.0",
|
||||||
"css-minimizer-webpack-plugin": "^3.0.1",
|
"esbuild-sass-plugin": "^2.8.0",
|
||||||
|
"esbuild-wasm": "^0.17.16",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
"eslint-config-react-app": "^7.0.0",
|
"eslint-config-react-app": "^7.0.0",
|
||||||
"eslint-config-standard": "^17.0.0-1",
|
"eslint-config-standard": "^17.0.0-1",
|
||||||
|
|
@ -36,22 +32,15 @@
|
||||||
"eslint-plugin-promise": "^6.0.0",
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.4.0",
|
"eslint-plugin-react-hooks": "^4.4.0",
|
||||||
"eslint-webpack-plugin": "^3.1.1",
|
|
||||||
"htmlparser": "^1.7.7",
|
"htmlparser": "^1.7.7",
|
||||||
"jed": "^1.1.1",
|
"jed": "^1.1.1",
|
||||||
"mini-css-extract-plugin": "^2.5.3",
|
|
||||||
"po2json": "^1.0.0-alpha",
|
"po2json": "^1.0.0-alpha",
|
||||||
"qunit": "^2.9.3",
|
"qunit": "^2.9.3",
|
||||||
"sass": "^1.35.2",
|
"sass": "^1.61.0",
|
||||||
"sass-loader": "^12.1.0",
|
|
||||||
"sizzle": "^2.3.3",
|
"sizzle": "^2.3.3",
|
||||||
"string-replace-loader": "^3.0.0",
|
|
||||||
"stylelint": "^14.9.1",
|
"stylelint": "^14.9.1",
|
||||||
"stylelint-config-standard-scss": "^5.0.0",
|
"stylelint-config-standard-scss": "^5.0.0",
|
||||||
"stylelint-webpack-plugin": "^3.3.0",
|
"stylelint-formatter-pretty": "^3.2.0"
|
||||||
"terser-webpack-plugin": "^5.1.4",
|
|
||||||
"webpack": "^5.54.0",
|
|
||||||
"webpack-cli": "^4.9.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@patternfly/patternfly": "4.224.4",
|
"@patternfly/patternfly": "4.224.4",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ appstream-util validate-relax --nonet %{buildroot}/%{_datadir}/metainfo/*
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%doc README.md
|
%doc README.md
|
||||||
%license LICENSE dist/index.js.LICENSE.txt.gz
|
%license LICENSE dist/index.js.LEGAL.txt dist/index.css.LEGAL.txt
|
||||||
%{_datadir}/cockpit/*
|
%{_datadir}/cockpit/*
|
||||||
%{_datadir}/metainfo/*
|
%{_datadir}/metainfo/*
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,8 @@ along with this package; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="index.css">
|
||||||
|
|
||||||
<script type="text/javascript" src="../base1/cockpit.js"></script>
|
|
||||||
<script type="text/javascript" src="po.js"></script>
|
|
||||||
<script type="text/javascript" src="index.js"></script>
|
<script type="text/javascript" src="index.js"></script>
|
||||||
|
<script type="text/javascript" src="po.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="pf-m-redhat-font">
|
<body class="pf-m-redhat-font">
|
||||||
|
|
|
||||||
4
test/run
4
test/run
|
|
@ -7,4 +7,8 @@ set -eu
|
||||||
TEST_SCENARIO="${TEST_SCENARIO:-}"
|
TEST_SCENARIO="${TEST_SCENARIO:-}"
|
||||||
[ "${TEST_SCENARIO}" = "${TEST_SCENARIO##firefox}" ] || export TEST_BROWSER=firefox
|
[ "${TEST_SCENARIO}" = "${TEST_SCENARIO##firefox}" ] || export TEST_BROWSER=firefox
|
||||||
export RUN_TESTS_OPTIONS=--track-naughties
|
export RUN_TESTS_OPTIONS=--track-naughties
|
||||||
|
|
||||||
|
# linters are off by default for production builds, but we want to run them in CI
|
||||||
|
export LINT=1
|
||||||
|
|
||||||
make check
|
make check
|
||||||
|
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
import copy from "copy-webpack-plugin";
|
|
||||||
import extract from "mini-css-extract-plugin";
|
|
||||||
import TerserJSPlugin from 'terser-webpack-plugin';
|
|
||||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
|
||||||
import CompressionPlugin from "compression-webpack-plugin";
|
|
||||||
import ESLintPlugin from 'eslint-webpack-plugin';
|
|
||||||
import StylelintPlugin from 'stylelint-webpack-plugin';
|
|
||||||
|
|
||||||
import { CockpitPoWebpackPlugin } from './pkg/lib/cockpit-po-plugin.js';
|
|
||||||
import { CockpitRsyncWebpackPlugin } from "./pkg/lib/cockpit-rsync-plugin.js";
|
|
||||||
|
|
||||||
/* A standard nodejs and webpack pattern */
|
|
||||||
const production = process.env.NODE_ENV === 'production';
|
|
||||||
|
|
||||||
/* development options for faster iteration */
|
|
||||||
const eslint = process.env.ESLINT !== '0';
|
|
||||||
|
|
||||||
/* Default to disable csslint for faster production builds */
|
|
||||||
const stylelint = process.env.STYLELINT ? (process.env.STYLELINT !== '0') : !production;
|
|
||||||
|
|
||||||
// Obtain package name from package.json
|
|
||||||
const packageJson = JSON.parse(fs.readFileSync('package.json'));
|
|
||||||
|
|
||||||
// Non-JS files which are copied verbatim to dist/
|
|
||||||
const copy_files = [
|
|
||||||
"./src/index.html",
|
|
||||||
"./src/manifest.json",
|
|
||||||
];
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
new copy({ patterns: copy_files }),
|
|
||||||
new extract({ filename: "[name].css" }),
|
|
||||||
new CockpitPoWebpackPlugin(),
|
|
||||||
new CockpitRsyncWebpackPlugin({ dest: packageJson.name }),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (eslint) {
|
|
||||||
plugins.push(new ESLintPlugin({ extensions: ["js", "jsx"], failOnWarning: true, }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stylelint) {
|
|
||||||
plugins.push(new StylelintPlugin({
|
|
||||||
context: "src/",
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only minimize when in production mode */
|
|
||||||
if (production) {
|
|
||||||
plugins.unshift(new CompressionPlugin({
|
|
||||||
test: /\.(js|html|css)$/,
|
|
||||||
deleteOriginalAssets: true
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
mode: production ? 'production' : 'development',
|
|
||||||
resolve: {
|
|
||||||
modules: ["node_modules", 'pkg/lib'],
|
|
||||||
alias: { 'font-awesome': 'font-awesome-sass/assets/stylesheets' },
|
|
||||||
},
|
|
||||||
resolveLoader: {
|
|
||||||
modules: ["node_modules", 'pkg/lib'],
|
|
||||||
},
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/,
|
|
||||||
},
|
|
||||||
entry: {
|
|
||||||
index: "./src/index.js",
|
|
||||||
},
|
|
||||||
// cockpit.js gets included via <script>, everything else should be bundled
|
|
||||||
externals: { cockpit: "cockpit" },
|
|
||||||
devtool: "source-map",
|
|
||||||
stats: "errors-warnings",
|
|
||||||
// always regenerate dist/, so make rules work
|
|
||||||
output: { clean: true, compareBeforeEmit: false },
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
minimize: production,
|
|
||||||
minimizer: [
|
|
||||||
new TerserJSPlugin({
|
|
||||||
extractComments: {
|
|
||||||
condition: true,
|
|
||||||
filename: `[file].LICENSE.txt?query=[query]&filebase=[base]`,
|
|
||||||
banner(licenseFile) {
|
|
||||||
return `License information can be found in ${licenseFile}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new CssMinimizerPlugin()
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: "babel-loader",
|
|
||||||
test: /\.(js|jsx)$/
|
|
||||||
},
|
|
||||||
/* HACK: remove unwanted fonts from PatternFly's css */
|
|
||||||
{
|
|
||||||
test: /patternfly-4-cockpit.scss$/,
|
|
||||||
use: [
|
|
||||||
extract.loader,
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
url: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'string-replace-loader',
|
|
||||||
options: {
|
|
||||||
multiple: [
|
|
||||||
{
|
|
||||||
search: /src:url\("patternfly-icons-fake-path\/pficon[^}]*/g,
|
|
||||||
replace: 'src:url("../base1/fonts/patternfly.woff") format("woff");',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
search: /@font-face[^}]*patternfly-fonts-fake-path[^}]*}/g,
|
|
||||||
replace: '',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: !production,
|
|
||||||
sassOptions: {
|
|
||||||
outputStyle: production ? 'compressed' : undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.s?css$/,
|
|
||||||
exclude: /patternfly-4-cockpit.scss/,
|
|
||||||
use: [
|
|
||||||
extract.loader,
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true,
|
|
||||||
url: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: !production,
|
|
||||||
sassOptions: {
|
|
||||||
outputStyle: production ? 'compressed' : undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue