How to bundle and minimize JS and CSS files with webpack - javascript

I have been trying to use webpack for my project. I have successfully got webpack to compile all of my js into one file correctly. But what i need is for it to also get the css. All of my css is in one file so i figured it would be easy but i cant figure it out. I have tried to split it up into 2 phases CSS_CONFIG and JS_CONFIG
const path = require('path');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
var JS_CONFIG = {
entry: path.join(__dirname, 'src/js/main.js'),
resolve: {
alias: {
'/components': path.resolve(__dirname, 'src/components/'),
'/js': path.resolve(__dirname, 'src/js/'),
'/views': path.resolve(__dirname, 'src/views/'),
},
},
optimization: {
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
new TerserPlugin(),
//new CssMinimizerPlugin(),
],
},
}
var CSS_CONFIG = {
entry:path.join(__dirname,"src/index.html"),
module: {
rules: [
{
test: /.s?css$/,
use: [],
},
],
},
optimization: {
minimize:true,
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`,
//new CssMinimizerPlugin(),
],
},
plugins: [],
}
module.exports = [JS_CONFIG, CSS_CONFIG];
This seems like it should be pretty straightforward with webpack but I must not be grasping somthing. Can anyone help me out?

I believe that your CSS_CONFIG should look more like this:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const isDevelopment = process.env.NODE_ENV === 'development'
var config = {
module: {},
};
var cssConfig = Object.assign({}, config, {
devtool: 'source-map',
entry: {
main: path.resolve(__dirname, 'public/css/main.scss'),
fonts: path.resolve(__dirname, 'public/css/fonts.scss'),
app: path.resolve(__dirname, 'public/css/app.scss'),
},
output: {
path: path.resolve(__dirname, 'public/css')
},
performance: {
hints: false
},
plugins: isDevelopment ? [] : [
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
],
module: {
rules:[
// Extracts the compiled CSS from the SASS files defined in the entry
{
test: /\.scss$/,
use: isDevelopment ?
[
'style-loader',
{
loader: 'css-loader',
options: { sourceMap: true, importLoaders: 1, modules: false },
},
{
loader: 'postcss-loader',
options: { sourceMap: true }
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
]
: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
// publicPath is the relative path of the resource to the context
// e.g. for ./css/admin/main.css the publicPath will be ../../
// while for ./css/main.css the publicPath will be ../
return path.relative(path.dirname(resourcePath), context) + "/";
},
},
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: false,
url: false,
},
},
{
loader: 'postcss-loader',
options:
{
postcssOptions:
{
plugins: [
require('postcss-import'),
require('postcss-url')({
url: 'copy',
useHash: true,
hashOptions: { append: true },
assetsPath: path.resolve(__dirname, 'public/assets/')
})
]
}
}
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
]
},
/* you may or may not need this
{
test: /\.(woff(2)?|ttf|eot|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/',
esModule: false,
}
}
]
},
*/
],
}
});

use runs the loaders in order that they are put in the array. So 'style-loader' needs to be executed first. Here is a simple way of achieving the desired result.
const path = require('path');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts');
const isDevelopment = process.env.NODE_ENV === 'development'
var JS_CONFIG = {
entry: {
main: path.resolve(__dirname, 'src/js/main.js'),
css: path.join(__dirname, 'src/css/main.css'),
},
resolve: {
alias: {
'/components': path.resolve(__dirname, 'src/components/'),
'/js': path.resolve(__dirname, 'src/js/'),
'/views': path.resolve(__dirname, 'src/views/'),
},
},
module: {
rules:[
{
test: /\.css$/,
use:['style-loader','css-loader']
},
],
},
};
module.exports = [JS_CONFIG];

Related

'Cannot find module' when using dynamic import

I've deleted CRA and configured webpack/babel on my own. Now I have problems with dynamic imports.
This works fine:
import("./" + "CloudIcon" + ".svg")
.then(file => {
console.log(file);
})
This doesn't work:
const name = 'CloudIcon';
import("./" + name + ".svg")
.then(file => {
console.log(file);
})
I've tried to export files with different types. It didn't work.
Have tried to use Webpack Magic Comments, but didn't help either.
I suppose, that something is wrong with my webpack/babel settings, but what?
babel.config.js:
const plugins = [
"#babel/syntax-dynamic-import",
["#babel/plugin-transform-runtime"],
"#babel/transform-async-to-generator",
"#babel/plugin-proposal-class-properties"
];
if (process.env.NODE_ENV === 'development') {
plugins.push('react-refresh/babel');
}
module.exports = {
presets: [[
"#babel/preset-env", {
"debug": false,
"modules": false,
"useBuiltIns": false
}],
['#babel/preset-react', {throwIfNamespace: false}],
'#babel/preset-typescript'
],
plugins,
};
webpack.config.js:
require('dotenv').config();
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ReactRefreshWebpackPlugin = require('#pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const reactAppVars = (() => {
const obj = {};
for (let key in process.env) {
if (key.startsWith('REACT_APP_')) obj[key] = process.env[key];
}
return obj;
})();
const target = process.env['NODE_ENV'] === 'production' ? 'browserslist' : 'web';
const plugins = [
new webpack.EnvironmentPlugin({'NODE_ENV': process.env['NODE_ENV'], 'PUBLIC_URL': '', ...reactAppVars}),
new HtmlWebpackPlugin({template: path.resolve(__dirname, '../public/index.html')}),
new MiniCssExtractPlugin({filename: '[name].[contenthash].css'}),
new webpack.ProvidePlugin({process: 'process/browser'}),
new webpack.ProvidePlugin({"React": "react"}),
];
if (process.env['SERVE']) plugins.push(new ReactRefreshWebpackPlugin());
const proxy = {
//Proxy settings
}
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "../build"),
assetModuleFilename: '[path][name].[ext]'
},
plugins,
devtool: 'source-map',
devServer: {
static: {
directory: path.resolve(__dirname, "../public"),
},
proxy,
port: 9999,
hot: true,
},
module: {
rules: [
{ test: /\.(html)$/, use: ['html-loader'] },
{
test: /\.(s[ac]|c)ss$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
},
{
test: /\.less$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true
}
}
}
]
},
{
test: /\.(png|jpe?g|gif|webp|ico)$/i,
type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
},
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['#svgr/webpack', {
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}],
},
{
test: /\.(woff2?|eot|ttf|otf)$/i,
type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
}
},
{
test: /\.([cm]?ts|tsx)$/,
use: {
loader: "babel-loader",
options: {
presets: [
"#babel/preset-env",
"#babel/preset-react",
"#babel/preset-typescript",
]
}
}
},
{
test: /\.md$/,
loader: "raw-loader"
},
],
},
resolve: {
'roots': [path.resolve('./src')],
'extensions': ['', '.js', '.jsx', '.ts', '.tsx'],
extensionAlias: {
".js": [".js", ".ts"],
".cjs": [".cjs", ".cts"],
".mjs": [".mjs", ".mts"]
},
fallback: {
'process/browser': require.resolve('process/browser')
}
},
mode: process.env['NODE_ENV'],
target
}
What is basically happen that when you have defined import path, webpack will include that code in already existing chunk.
When you have a dynamic import (which translated to Regex) it will take all files that correspond to this Regex and place them in a different chunk.
It hard to determine from the details if you serve this additional chunks and the browser can reach them. Network and server logs is a good start.
https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules
The problem was the extensions array in webpack
'extensions': ['', '.js', '.jsx', '.ts', '.tsx']
I changed it to this
'extensions': ['.js', '.jsx', '.ts', '.tsx', '...']
And now everything works fine.

Webpack 5 SCSS and JS save returns old version of page

I work with webpack 5. Pug works well - after autosave or cmd+S I get new version of page. And it doesn't work so with JS and SCSS: SCSS autosave works well but after cmd+S I get some old version of page(usually everytime the same). With JS both autosave and cmd+S return some old version of page. Can you help me to find a solution? Below I dropped webpack.config.js
const path = require("path");
const fs = require("fs");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const isDev = process.env.NODE_ENV === "development";
const isProd = !isDev;
const PATHS = {
src: path.join(__dirname, "./src"),
dist: path.join(__dirname, "./dist"),
};
const PAGES_DIR = `${PATHS.src}/`;
const PAGES = fs.readdirSync(PAGES_DIR).filter((fileName) => fileName.endsWith(".pug"));
const filename = (ext) => `[name].${ext}`;
const plugins = () => {
const basePlugins = [
...PAGES.map(
(page) =>
new HTMLWebpackPlugin({
template: `${PAGES_DIR}/${page}`,
filename: `./${page.replace(/\.pug/, ".html")}`,
})
),
new MiniCssExtractPlugin({
filename: `./css/${filename("css")}`,
}),
new CopyWebpackPlugin({
patterns: [
{ from: path.resolve(__dirname, "src/assets"), to: path.resolve(`${PATHS.dist}`) },
{ from: path.resolve(__dirname, "src/img"), to: path.resolve(`${PATHS.dist}/img/`) },
],
}),
];
return basePlugins;
};
module.exports = {
context: path.resolve(`${PATHS.src}`),
mode: "development",
entry: "./js/main.js",
output: {
filename: `./js/${filename("js")}`,
path: path.resolve(`${PATHS.dist}`),
publicPath: "",
clean: true,
},
devServer: {
historyApiFallback: true,
static: path.resolve(`${PATHS.dist}`),
open: true,
compress: true,
hot: true,
port: 3000,
},
optimization: {
splitChunks: {
chunks: "all",
},
},
plugins: plugins(),
devtool: isProd ? false : "source-map",
module: {
rules: [
{
test: /\.pug$/,
loader: "pug-loader",
},
{
test: /\.s[ac]ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: (resourcePath, context) => {
return path.relative(path.dirname(resourcePath), context) + "/";
},
},
},
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
"sass-loader",
],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /\.(?:|gif|png|jpg|jpeg|svg|webp)$/,
use: [
{
loader: "file-loader",
options: {
name: `./img/${filename("[ext]")}`,
},
},
],
},
{
test: /\.(?:|woff2)$/,
use: [
{
loader: "file-loader",
options: {
name: `./fonts/${filename("[ext]")}`,
},
},
],
},
],
},
};
I don't know what to write here. I described my problem above.

How to ignore error js script tag from html on running webpack with HtmlWebpackPlugin?

How can i ignore the script tag in Html webpack plugin?
Because I have added this
<script src="cordova.js"/>
tag into my index.html template anonymously for my app development.
See my configuration in Webpack.config.js:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: ["html-loader"],
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
I just wanted to ignore the script on production and I have researched this many times but unfortunately I don't see any solution
So, if I got the problem right, you want to ignore a certain resource when bundling for production.
The html-loader has an option to filter sources based on attribute, attribute value, context file and anything you have available in you webpack.config.js.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Assuming you are passing arguments to your webpack config like argv.mode
const PRODUCTION = true;
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "www"),
filename: "./js/build/[name].build.js",
chunkFilename: "./js/build/[name].build.js",
// publicPath: "./js/build/",
},
module: {
rules: [
{
test: /\.m?js$/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "./",
},
},
"css-loader?url=false",
"sass-loader",
],
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
sources: {
urlFilter: (attribute, value, resourcePath) => {
if (PRODUCTION && /cordova.js$/.test(value)) {
return false;
}
return true;
},
}
},
},
},
{
test: /\.(svg|png|jpeg|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "res",
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "./css/build/[name].css",
// chunkFilename: "../css/[id].css"
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
// new BundleAnalyzerPlugin()
],
// devtool: "inline-source-map",
};
In the html module rule, I added an options property to html-loader with an example how you could ignore a certain resource with urlFilter. Check the html-loader docs on filtering resources
You will need to get a reference to the variables you passed to your cli like --mode eg. line 5-6. (Not in the current example) See webpack docs on env vars.

Webpack unexpected behavior TypeError: Cannot read property 'call' of undefined

Recently we have updated webpack to v4 and soon noticed unexpected errors from webpack during development, which disappears after rebuild of entire bundle.
Our application build using lazy loading and code splitting, which can cause the issue, though I couldn't find anything related to this in the official documentations.
Here the error we get
react_devtools_backend.js:2273 TypeError: Cannot read property 'call' of undefined
our webpack webpack.config.js file.
const webpack = require('webpack');
const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
// minification plugins
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// image optimization plugins
const ImageminPlugin = require("imagemin-webpack-plugin").default;
const imageminGifsicle = require("imagemin-gifsicle");
const imageminPngquant = require("imagemin-pngquant");
const imageminSvgo = require("imagemin-svgo");
const imageminMozjpeg = require('imagemin-mozjpeg');
const env = require('dotenv').config();
const isProd = process.env.NODE_ENV === 'production';
const isDev = !isProd;
const environment = {
NODE_ENV: process.env.NODE_ENV || 'development',
CONFIG: process.env.CONFIG || 'development',
DEBUG: process.env.DEBUG || false,
};
const plugins = () => {
let plugins = [
new CleanWebpackPlugin(['build', 'cachedImages'], {
root: path.resolve(__dirname, '../dist'),
verbose: true,
dry: false,
}),
new webpack.EnvironmentPlugin(Object.assign(environment, env.parsed)),
new MiniCssExtractPlugin('[chunkhash:5].[name].[hash].css'),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
moment: 'moment',
_: 'lodash',
}),
new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(en)$/),
new AssetsPlugin({
filename: 'assets.json',
}),
new ImageminPlugin({
cacheFolder: isDev ? path.resolve(__dirname, '../dist/cachedImages') : null,
externalImages: {
context: 'src',
sources: glob.sync('src/assets/img/**/*.*'),
destination: 'dist/img/',
fileName: (filepath) => {
let name = filepath.split(/img(\/|\\)/).pop();
return name;
},
},
plugins: [
imageminGifsicle({
interlaced: false
}),
imageminMozjpeg({
progressive: true,
arithmetic: false
}),
imageminPngquant({
floyd: 0.5,
speed: 2
}),
imageminSvgo({
plugins: [
{ removeTitle: true },
{ convertPathData: false }
]
}),
],
}),
];
if (isProd) {
plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: path.resolve(__dirname, 'analysis.html'),
generateStatsFile: false,
logLevel: 'info',
})
);
}
return plugins;
};
const optimization = () => {
let optimizations = {
concatenateModules: true,
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendor',
test: /[\\/]node_modules[\\/](react|react-dom|lodash|moment)[\\/]/,
chunks: 'all',
},
commons: {
chunks: 'async',
}
}
}
};
if (isProd) {
optimizations.minimizer = [
new TerserJSPlugin({
terserOptions: {
compress: {
pure_funcs: ['console.log'],
drop_console: true,
drop_debugger: true
},
warnings: false
},
parallel: true
}),
new OptimizeCSSAssetsPlugin({})
];
}
return optimizations;
};
const fontLoaders = [
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url?limit=10000&mimetype=application/font-woff',
}
},
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url?limit=10000&mimetype=application/font-woff',
}
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url?limit=10000&mimetype=application/octet-stream',
}
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url?limit=10000&mimetype=image/svg+xml',
}
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'file',
}
}
];
const config = {
mode: process.env.NODE_ENV,
devtool: isDev ? 'source-map' : '',
context: path.resolve(__dirname, '../src'),
entry: {
bundle: './app.jsx',
embed: './embed.jsx',
styles: './sass_new/main.scss',
vendor: [
'react',
'react-dom',
'redux',
'redux-saga',
'react-redux',
'react-router',
'react-tap-event-plugin',
'lodash',
'moment',
]
},
output: {
publicPath: '/build/',
filename: '[name].[hash].js',
chunkFilename: '[name].[hash].js',
path: path.resolve(__dirname, '../dist/build'),
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
config: path.resolve(__dirname, '../config.js'),
utils: path.resolve(__dirname, '../src/utils'),
shared: path.resolve(__dirname, '../src/components/shared'),
services: path.resolve(__dirname, '../src/services'),
store: path.resolve(__dirname, '../src/store'),
constants: path.resolve(__dirname, '../src/constants'),
actions: path.resolve(__dirname, '../src/actions'),
components: path.resolve(__dirname, '../src/components'),
},
},
optimization: optimization(),
plugins: plugins(),
module: {
rules: [
{
test: /\.jsx?$/,
exclude: [/node_modules/, /libs/],
use: {
loader: path.join(__dirname, '../helpers/custom-loader.js'),
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
'#babel/plugin-proposal-object-rest-spread',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-transform-destructuring',
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-transform-runtime',
'syntax-async-functions'
]
}
}
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
'sass-loader',
]
},
{
test: /\.css$/,
use: [
'css-loader'
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "url-loader",
options: {
name: "[path][name].[ext]"
},
},
...fontLoaders
]
},
watchOptions: {
ignored: /node_modules/,
},
};
module.exports = config;
I have no idea how to fix this, and it's taking a lot of time to rebuild entire app after getting this error.

Webpack Build Speed performance

The Webpack Bulid runs pretty slow, project background is a community portal developed in Vue.js...
Can anybody tell if there is any potential for improvement and if so, what?
I wonder if the time for the build process of 37401ms can still be changed by changing the codebase?
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const glob = require('glob');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');
const statsSettings = {
all: false,
modules: true,
maxModules: 0,
errors: true,
warnings: false,
moduleTrace: true,
errorDetails: true,
timings: true,
performance: true,
builtAt: true,
};
const {
rootDir,
srcDir,
assetsDir,
stylesDir,
buildDir,
sitepackageDir,
publicPath,
} = require('./config');
const chunks = glob.sync(path.join(rootDir, srcDir, 'pages/**/index.js'))
.reduce((obj, file) => {
const name = path.basename(path.dirname(file));
return {
...obj,
[name]: file,
};
}, {});
module.exports = env => {
return {
mode: env.production ? 'production' : 'development',
context: path.join(rootDir, srcDir),
entry: chunks,
output: {
path: path.join(rootDir, buildDir),
filename: '[name].js',
publicPath: env.production ? publicPath : '',
},
devtool: env.production ? false : 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(rootDir, buildDir),
inline: true,
proxy: {
'/api/v0': 'http://localhost:4000',
},
},
watchOptions: {
ignored: env.watch ? 'node_modules' : '',
aggregateTimeout: 300,
},
stats: env.watch ? statsSettings : 'normal',
module: {
rules: [
{
test: /\.vue$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'vue-loader',
},
{
test: /\.js$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'babel-loader',
},
{
test: /\.(css|scss)$/,
use: [
env.production ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['>1%', 'last 2 versions', 'not ie < 11'],
}),
],
},
},
{
loader: 'sass-loader',
options: {
includePaths: [
path.join(rootDir, srcDir, stylesDir),
],
},
},
],
},
{
test: /\.(jpg|jpeg|png|gif|webp|svg|eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/,
loader: 'file-loader',
options: {
name: `${assetsDir}/_processed_/[name].[hash:4].[ext]`,
},
},
],
},
optimization: {
runtimeChunk: {
name: '_runtime',
},
splitChunks: {
cacheGroups: {
// we need to figure out if it's worth having a common chunk
// or if each entry chunk should be somewhat self-contained
common: {
chunks: 'initial',
name: '_common',
minChunks: 2,
minSize: 0,
},
vendor: {
test: /node_modules/,
chunks: 'initial',
name: '_vendor',
enforce: true,
},
},
},
},
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
'#app': path.join(rootDir, srcDir),
// although we're using single file components that can be pre-compiled,
// we want to dynamically mounting them in the DOM html.
// this is way we need to alias 'vue' to use the runtime + compiler build here.
// see: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.DefinePlugin({
PAGES: JSON.stringify(Object.keys(chunks)),
}),
new VueLoaderPlugin(),
...plugHtmlTemplates(),
...plugExtractCss(env),
...plugCopyAssets(),
],
};
};
function plugHtmlTemplates () {
return glob.sync(path.join(rootDir, srcDir, 'pages/**/template.html'))
.map(template => {
const name = path.basename(path.dirname(template));
return {
template,
filename: `${name}.html`,
chunks: ['_runtime', '_vendor', '_styles', '_common', name],
};
})
.map(htmlConfig => new HtmlWebpackPlugin(htmlConfig));
}
function plugExtractCss (env) {
if (!env.production) return [];
return [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].css',
}),
];
}
function plugCopyAssets () {
const assetsSrcPath = path.join(rootDir, srcDir, assetsDir);
if (!fs.existsSync(assetsSrcPath)) return [];
return [
new CopyWebpackPlugin([
{ from: assetsSrcPath, to: path.join(rootDir, buildDir, path.basename(assetsDir)) },
// this is required for the icons to be selectable in the backend
{ from: path.join(assetsSrcPath, 'icons/'), to: path.join(rootDir, sitepackageDir, 'Resources/Public/Icons/') },
// this is required for avatars to be available; we must not check them in in fileadmin since they would
// prevent having the dir linked by Deployer during a deployment
{ from: path.join(rootDir, '../packages/users/Resources/Private/Images/Avatars/'), to: path.join(rootDir, buildDir, 'static/avatars/') },
]),
];
}
The question is whether you can improve the performance by using different plugins or summarizing steps...
I have a similar configuration. My configuration built ~33 seconds. I added a cache-loader package and decrease build time to ~17 seconds.
npm install --save-dev cache-loader
config:
rules: [
//rules here
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'vue-loader',
options: vueLoaderConfig
}
],
},
{
test: /\.js$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'babel-loader'
}
],
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
]

Categories

Resources