Create vendor.bundle for each entry with webapack 4 - javascript

I want to make vendor.bundle for each entry with webapack4.
example.
src/
pages/
home/
index.js
list/
index.js
After building.
dist/
pages/
home/
index.bundle.js
home.vendor.bundle.js
list/
index.bundle.js
list.vendor.bundle.js
How do I configure split chunks?
Current config.
const path = require('path')
module.exports = {
mode: 'development',
entry: {
'/pages/home/index': path.resolve(__direname, 'src', 'pages', 'home', 'index.js'),
'/pages/list/index': path.resolve(__direname, 'src', 'pages', 'list', 'index.js'),
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
// I am troubled with the setting here.
optimization: {
runtimeChunk: {
name: 'runtime'
},
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true,
name: 'vendor'
},
}
}
},
}
I tried to handle name with a function instead of a string, but it did not work.
Thank you.

Solved this problem.
const path = require('path')
module.exports = {
mode: 'development',
entry: {
'/pages/home/index': path.resolve(__direname, 'src', 'pages', 'home', 'index.js'),
'/pages/list/index': path.resolve(__direname, 'src', 'pages', 'list', 'index.js'),
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
optimization: {
runtimeChunk: {
name: 'runtime'
},
splitChunks: {
cacheGroups: {
'top-vendor': {
test: /[\\/]node_modules[\\/]/,
chunks: chunk => chunk.name === '/pages/home/index',
enforce: true,
name: `${path.dirname('/pages/home/index')}/vendor`
},
'list-vendor': {
test: /[\\/]node_modules[\\/]/,
chunks: chunk => chunk.name === '/pages/list/index',
enforce: true,
name: `${path.dirname('/pages/list/index')}/vendor`
},
}
}
},
}

Related

How i can solve the devServer problem in webpack?

I would be grateful for any help or advice. I have compiled the configuration of the webpack, everything works in production mode, but the webpack-dev-server does not see static files and gives the error "Cannot get /". How can I solve this problem? Thank you in advance for the answer. Here is my webpack.config.js
const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
// const autoprefixer = require("autoprefixer");
const isProd = process.env.NODE_ENV === "production";
const isDev = !isProd;
const optimization = () => {
const config = {
runtimeChunk: "single",
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: -10,
chunks: "all",
},
},
},
};
if (isProd) {
config.minimizer = [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
];
}
return config;
};
module.exports = {
entry: path.resolve(__dirname, "src", "index.js"),
mode: isProd ? "production" : "development",
output: {
path: path.join(__dirname, "build"),
filename: "[name].[contenthash:8].js",
chunkFilename: "[name].[contenthash:8].js",
publicPath: "./",
},
devtool: isDev ? "source-map" : false,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.(eot|ttf|woff|woff2)(\?\S*)?$/,
loader: "file-loader",
options: {
name: "[name][contenthash:8].[ext]",
},
},
{
test: /\.(png|jpe?g|gif|webm|mp4|svg)$/,
loader: "file-loader",
options: {
name: "[name][contenthash:8].[ext]",
outputPath: "assets/img",
esModule: false,
},
},
{
test: /\.s?css$/,
use: [
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: false,
},
},
"css-loader",
],
},
],
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: "[name].[contenthash:8].css",
chunkFilename: "[name].[contenthash:8].css",
}),
new HTMLWebpackPlugin({
template: path.join(__dirname, "src", "public", "index.html"),
filename: "start-page.html",
alwaysWriteToDisk: true,
minify: {
collapseWhitespace: isProd,
},
}),
new CleanWebpackPlugin(),
],
resolve: {
alias: {
vue: "#vue/runtime-dom",
},
extensions: ["*", ".js", ".vue", ".json"],
},
optimization: optimization(),
devServer: {
compress: true,
port: 9000,
hot: true,
client: {
overlay: true,
},
},
};
Here is a project folders
According to the doc, you need to set the publicPath in the devServer.
Look at the documentation
module.exports = {
//...
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
},
};

Webpack multiple HTML - I need only to inject one .js for each HTML

Hi I have the following problem with my Webpack Config:
I want to have 3 different .js files from my src folder. Each file is supposed to be connected to only the corresponding html file with the same name:
Example: I want app.html only to inject app.js and not index.js and register.js as well.
As for now, Webpack generates 3 html files and 3 .js files, however every .html file gets referenced all 3 .js files, which breaks my code, since I don't have the corresponding id's for eventlisteners in index that the code written app.js.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: ['./src/js/index.js'],
register: ['./src/js/register.js'],
app: ['./src/js/app.js'],
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
devServer: {
contentBase: './dist'
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
chunks: 'index',
template:'./src/index.html',
filename: './src/index.html'
}),
new HtmlWebpackPlugin({
inject: true,
chunks: 'register',
template:'./src/register.html',
filename: './src/register.html'
}),
new HtmlWebpackPlugin({
inject: true,
chunks: 'app',
template:'./src/app.html',
filename: './src/app.html'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
Here you have an example adding one chunks to the html
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const config = [{
site: 'index'
}, {
site: 'register'
}, {
site: 'app'
}];
const entryHtmlPlugins = config.map(({
site
}) => {
return new HtmlWebPackPlugin({
filename: `${site}.html`,
chunks: [site],
});
});
module.exports = {
mode: 'production',
entry: {
index: './src/js/index.js',
register: './src/js/register.js',
app: './src/js/app.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
}, ],
},
plugins: [...entryHtmlPlugins],
};

Multiple assets emit different content to the same filename index.html

My webpack config gives the following error Multiple assets emit different content to the same filename index.html
when I delete the htmlWebpackPlugin it works, but I won't get any html to show. I'm using Vue.js and my config looks like this:
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = (env, argv) => ({
mode: argv && argv.mode || 'development',
devtool: (argv && argv.mode || 'development') === 'production' ? 'source-map' : 'eval',
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
node: false,
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
exclude: /\.module\.css$/
}
]
},
resolve: {
extensions: [
'.js',
'.vue',
'.json'
],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': path.resolve(__dirname, 'src')
}
},
plugins: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['dist']
}),
new VueLoaderPlugin(),
new HtmlWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [{
from: path.resolve(__dirname, 'static'),
to: path.resolve(__dirname, 'dist'),
toType: 'dir'
}]
})
],
devServer: {
compress: true,
host: 'localhost',
https: true,
open: true,
overlay: true,
port: 9000
}
});
My file structure looks like this
I've looked at Conflict: Multiple assets emit to the same filename but no solution worked for me, are there any other options?
Could it be that Vue loader also emits index.html?
Try:
new HtmlWebpackPlugin({
template: './index.html',
filename: 'anotherFileName.html',
}),

Webpack in watch mode takes too long to build (~23s) after changes

After saving changes, webpack takes on average ~23 seconds to build. This is the output while it is building. It goes all the way up to 6695 modules before completing.
18% building 915/944 modules 29 active ...terial-ui/icons/esm/WallpaperTwoTone.js
How do I speed up the build time? Any help would be greatly appreciated.
node: 11.6
webpack: ^4.29.6
webpack.common.js:
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HappyPack = require('happypack');
// const HtmlWebpackPlugin = require('html-webpack-plugin')
const plugins = [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].css',
}),
new HappyPack({
id: 'html',
threads: 1,
loaders: ['html-loader']
}),
new HappyPack({
id: 'js',
threads: 1,
verbose: false,
debug: false,
loaders: ['babel-loader?cacheDirectory']
}),
new HappyPack({
id: 'css',
threads: 1,
loaders: ['css-loader']
}),
new HappyPack({
id: 'less',
threads: 1,
loaders: ['css-loader', 'less-loader']
}),
new ConcatPlugin({
sourceMap: false,
outputPath: 'css',
fileName: 'framework.css',
filesToConcat: [
'./node_modules/bootstrap/dist/css/bootstrap.css',
'./node_modules/material-design-icons-iconfont/dist/material-design-icons.css',
'./node_modules/ui-select/dist/select.min.css',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap-csp.css',
'./node_modules/angular-loading-bar/build/loading-bar.css',
'./node_modules/typeface-roboto/index.css'
],
attributes: {
async: true
}
}),
new ConcatPlugin({
sourceMap: false,
outputPath: 'js',
fileName: 'angular.bundle.min.js',
filesToConcat: [
'./node_modules/jquery/dist/jquery.js',
'./node_modules/angular/angular.js',
'./node_modules/angular-route/angular-route.min.js',
'./node_modules/angular-cookies/angular-cookies.min.js',
'./node_modules/angular-resource/angular-resource.min.js',
'./node_modules/angular-sanitize/angular-sanitize.min.js',
'./node_modules/angular-animate/angular-animate.min.js',
'./node_modules/bootstrap/dist/js/bootstrap.js'
],
attributes: {
async: true
}
}),
new ConcatPlugin({
sourceMap: false,
outputPath: 'js',
fileName: 'lib.js',
filesToConcat: [
'./node_modules/ui-select/dist/select.min.js',
'./node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js',
'./node_modules/angular-ui-mask/dist/mask.min.js',
'./node_modules/angular-ui-indeterminate/dist/indeterminate.min.js',
'./node_modules/angular-ui-event/dist/event.min.js',
'./node_modules/angular-ui-validate/dist/validate.min.js',
'./node_modules/angular-ui-uploader/dist/uploader.min.js',
'./node_modules/angular-input-masks/releases/angular-input-masks-standalone.js',
'./node_modules/angular-file-saver/dist/angular-file-saver.bundle.js',
'./node_modules/angular-loading-bar/build/loading-bar.js',
'./node_modules/angular-pageslide-directive/dist/angular-pageslide-directive.js',
'./node_modules/ng-idle/angular-idle.js'
],
attributes: {
async: true
}
}),
new CopyPlugin([
{
from: './node_modules/bootstrap/dist/fonts/*',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'build', 'fonts'),
flatten: true
},
{
from: './node_modules/material-design-icons-iconfont/dist/fonts/*',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'build', 'css', 'fonts'),
flatten: true
},
{
from: './node_modules/typeface-roboto/files/*',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'build', 'css', 'files'),
flatten: true
},
{
from: './static_files/img/*.svg',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'build', 'img'),
flatten: true
},
{
from: './static_files/img/*.ico',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static'),
flatten: true
},
{
from: './static_files/pdf',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'pdf'),
flatten: true
},
{
from: './static_files/fonts',
to: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'fonts'),
flatten: true
}
])
];
const rules = [
{
test: /\.html$/,
loader: 'happypack/loader?id=html',
exclude: /node_modules/
},
{
test: /\.svg$/,
loader: 'svg-url-loader',
options: {
iesafe: true
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'happypack/loader?id=css']
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'happypack/loader?id=less']
},
{
test: /\.(png|woff|woff2|eot|ttf)$/,
loader: 'url-loader?limit=100000'
},
{
test: /\.(ts|tsx)?$/,
include: [
path.resolve(__dirname, 'js'),
path.resolve(__dirname, 'node_modules/array-move')
],
exclude: /e2e/,
use: [
{
loader: 'happypack/loader?id=js'
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
experimentalWatchApi: true,
}
},
{
loader: 'tslint-loader',
options: {
emitErrors: true,
formatter: 'codeFrame'
}
},
],
enforce: 'pre'
},
{
test: /\.m?jsx?$/,
include: [
path.resolve(__dirname, 'js'),
path.resolve(__dirname, 'node_modules/array-move')
],
exclude: /e2e/,
loader: 'happypack/loader?id=js'
}
];
module.exports = {
devtool: 'source-map',
cache: false,
parallelism: 30,
context: path.resolve(__dirname, ''),
entry: {
main: ['#babel/polyfill', './js/app.ts']
},
output: {
path: path.resolve(__dirname, '..', 'webapp', 'WEB-INF', 'static', 'build'),
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
sourceMapFilename: '[name].bundle.js.map'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 1,
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial"
},
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
}
}
}
},
module: {
rules: rules
},
stats: {
colors: true
},
resolve: {
extensions: ['.tsx', '.ts', '.js', 'jsx', '.css', '.less']
},
externals: {
angular: 'angular'
},
performance: {
hints: false
},
plugins: plugins
};
wepback.dev.js:
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common');
const CleanWebpackPlugin = require('clean-webpack-plugin');
process.traceDeprecation = false; // set to true if you want to find dep that is deprecated.
module.exports = merge(commonConfig, () => {
return {
mode: 'development',
performance: {
hints: 'warning'
},
watchOptions: {
aggregateTimeout: 300,
poll: 1000,
ignored: /node_modules/
},
plugins: [
new CleanWebpackPlugin() // Only for watch!
]
}
});
Script we use to start the build:
"hot_build": "npm run clean:static && webpack -w --mode development --config webpack.dev.js --progress"
I have a question why practically the dev version is the same as in the prod.
Only the prod version should contain MiniCssExtractPlugin.loader version dev style-loader.
dev
{
test: /\.(css|sass|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true
},
},
...
prod
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2
},
},
...
The same happens with the optimization section, you should only use it in the prod version.
Next issue #babel/polyfill is deprecated. Delete #babel/polyfill and add core-js instead and configure .babelrc accordingly.
The biggest problem is that every change you delete the built folders and everything is copied again by 'CopyPlugin'. Isn't it better to use webpack-dev-server for this?
And rebuild everything so that webpack.dev.js uses this.
Then the first time it will take a long time to build up but the changes you will make later will be very quick.

copy-webpack-plugin doesn't copy files

I try to just copy files to check simple webpack config. So I stuck trying to make copy-webpack-plugin to work - nothing happens: no copied files, no errors, nothing
Common config (webpack.common.js):
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const postCssPlugin = [
require('postcss-import'),
require('postcss-nested'),
require('postcss-simple-vars'),
require('autoprefixer')({
browsers: [
'last 3 versions',
'android 4.2'
]
})
];
module.exports = {
context: path.resolve(__dirname, '../src'),
entry: [
'babel-polyfill',
path.resolve(__dirname, '../src/index.js')
],
output: {
path: path.resolve(__dirname, '../dist/js'),
publicPath: '',
filename: 'app.js'
},
resolve: {
extensions: ['.jsx', '.js', '.json']
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.p?css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: postCssPlugin
}
}
]
}
]
},
plugins: [
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../src/assets/**/*'),
to: path.resolve(__dirname, '../dist/assets'),
flatten: true
}
])
],
stats: {
modules: true,
warnings: false,
version: true,
timings: true,
performance: false,
hash: true,
errors: true,
errorDetails: true,
colors: true,
builtAt: true
}
};
webpack.prod.js:
const commonWebpackConfig = require('./webpack.common.js');
const UglifyJsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = Object.assign(commonWebpackConfig, {
mode: 'production',
plugins: [
new UglifyJsWebpackPlugin({
sourceMap: true
})
]
});
And build starting file build.js:
const webpack = require('webpack');
const webpackProdConfig = require('./webpack.config/webpack.prod.js');
webpack(webpackProdConfig, (err, stats) => {
if (err || stats.hasErrors()) {
console.error(err.stack || err);
}
console.log('Successfully compiled!');
});
So could anyone figure out why doesn't it work and where am I wrong?
copy-webpack-plugin: 4.5.2
node: 9.1.0
npm: 6.3.0
windows: 10
Addition - folder structure:
Try to copy from the dist folder. For me it worked
es.
new CopywebpackPlugin([{
from: path.resolve(__dirname, 'node_modules/mettrr-component-library/dist/img'),
to: path.resolve(__dirname, 'src/assets/img')
}]),

Categories

Resources