preface

This article is a continuation of the previous one, “WebPack4 Builds a VUE project development Environment from scratch.” I highly recommend reading an article first.

This article mainly describes the differences between different environments and some points that can be optimized

The article demo has been submitted to Github, please download ———— “Webpack 4 Demo”

Distinguish between “development environment” and “Production Environment”

  • Development environment:Hot update,multithreading,sourceMap, etc.
  • Production environment:Js compressed,Extract the CSS,CSS compression,multithreading,sourceMap,Directory cleaning, etc.

Because the requirements of the “development environment” and the “production environment” are different, we build our projects in different environments.

configurationwebpack.common.jswebpack.dev.jswebpack.prod.js

Create a new build directory and create the following three files

  • webpack.common.jsCommon configuration
  • webpack.dev.jsDevelopment Environment Configuration
  • webpack.prod.jsGenerate environment configuration

The installationwebpack-merge

Used to merge the WebPack common configuration into the specified environment

NPM [email protected] - I DCopy the code

configurationwebpack.common.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
	entry: path.join(__dirname, ".. /src/main.js"),
	output: {
		path: path.join(__dirname, ".. /dist"),
		filename: "bundle.js"
	},
	module: {
		rules: [{test: /\.(png|jpg|gif)$/i,
				use: [
					{
						loader: 'url-loader'.options: {
							limit: 8192.// If the value is less than 8K, use URl-loader to convert to base64, otherwise use file-loader to process the file
							fallback: {
								loader: 'file-loader'.options: {
									name: '[name].[hash:8].[ext]'.outputPath: '.. /dist/images/'.// The path where the files are stored after packaging, dist/images}},}}]}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/,
				use: [
					{
						loader: 'url-loader'.options: {
							limit: 8192.fallback: {
								loader: 'file-loader'.options: {
									name: '[name].[hash:8].[ext]'.outputPath: '.. /dist/media/',}},}}]}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i,
				use: [
					{
						loader: 'url-loader'.options: {
							limit: 1.fallback: {
								loader: 'file-loader'.options: {
									name: '[name].[hash:8].[ext]'.outputPath: '.. /dist/fonts/',}},}}]}, {test: /\.(css)$/,
				use: [
						"style-loader"."css-loader"."postcss-loader"] {},test: /\.(less)$/,
					use: [
						"style-loader"."css-loader"."postcss-loader"."less-loader",]}, {test: /\.vue$/,
				use: ["vue-loader"]]}},plugins: [
		new HtmlWebpackPlugin({
			template: path.join(__dirname, '.. /src/index.html')}),new VueLoaderPlugin()
	]
};
Copy the code

configurationwebpack.dev.js

const webpack = require("webpack");
const { merge } = require('webpack-merge')
const webpackCommon = require('./webpack.common.js')
module.exports = merge(webpackCommon, {
	mode: "development".devServer: {
		contentBase: path.join(__dirname, ".. /dist"),
		compress: true.open: true.quiet: false.hot: true.// Start hot update
		port: 3000.clientLogLevel: 'none'.// Close the hot update output from the browser console
	},
	plugins: [
		new webpack.HotModuleReplacementPlugin()
	]
});
Copy the code

configurationwebpack.prod.js

const { merge } = require('webpack-merge')
const webpackCommon = require('./webpack.common.js')
module.exports = merge(webpackCommon, {
	mode: "production"
})
Copy the code

Modify thepackage.jsonNPM script

Specify that webPack executes different configuration files for different environments.

"Scripts ": {"serve": "webpack-dev-server --config build/webpack.dev.js", // "Webpack --config build/webpack.prod.js",// development environment},Copy the code

It is also possible to set process.env.node_env using –mode and execute different configuration file contents depending on whether the environment is “development” or “production”. I won’t do it here. There are also many examples on the Internet, interested in their own search ah

CleanWebpackPlugin automatically removes dist’s last packaged content

npm i clean-webpack-plugin -D
Copy the code
// webpack.prod.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [
	new CleanWebpackPlugin()
],
Copy the code

DefinePlugin sets the environment global variables

DefinePlugin is a built-in webPack plugin that does not need to be installed

configurationwebpack.dev.jswebpack.prod.js

Only webpack.dev.js is demonstrated here, and the webpack.prod.js Settings are the same.

Plugins: [new webpack.defineplugin ({'process.env': {// set global variables to call BASE_URL throughout the project: JSON.stringify('http://localhost:3000/dev') } }) ]Copy the code

Calling global variables

console.log('BASE_URL:', process.env.BASE_URL)
Copy the code

Set up thesourceMapEasy to debug

Bundle.js that is packaged by WebPack is compressed. Can’t debug properly. SourceMap is for debugging. If you’ve used vue-cli before, when you package it, you’ll have a.map file in the dist directory, which is the source mapping file.

We can set devTool to generate different types of sourceMap. Different patterns generate different code volumes, build speeds, security, and so on. See the webPack website.

Personal recommendation, the development environment recommends using the eval generation mode, it will be faster. As for cheap and Module, you can choose according to your own needs. For production environments, it is recommended to place sourceMap locally or on the Intranet for security purposes. This can be configured using the SourceMapDevToolPlugin.

  • The development environment
    devtool: "cheap-module-eval-source-map",
    Copy the code
  • The production environment

When using SourceMapDevToolPlugin, you need to set devtool: false. When using SourceMapDevToolPlugin, you need to set devtool: false.

//# sourceMappingURL= sourcemaps file path to the source code. When using browser debugging (F12), It will automatically look for the sourceMap for the path. We can customize this path in Append to support urls and local addresses

 // webpack.prod.js
  devtool: false.plugins: [
  	// By default, the generated schema is' source-map '
  	new webpack.SourceMapDevToolPlugin({
  		//sourcemap Indicates the Intranet address
  		append: '\n//# sourceMappingURL=http://localhost:1888/sourcemaps/[name].[hash:8].map'.// Generate the sourcemap directory and name
  		filename: 'sourcemaps/[name].[hash:8].map'.// Module :true // Equivalent to devtool module
  		// Columns :false //
  		// noSources:true // Equivalent to devtool noSources})].Copy the code

By the way, the vue-CLI “production environment” is generated as: devtool:source-map by default, which means the map file generated contains the uncompressed source code. The build speed is also extremely slow if the project is beating up

If you’re new to sourceMap, you may be confused, but the following article should help you

SourceMap recommends reading articles:

  • JavaScript Source Map
  • “What the hell are the seven SourceMap modes in DevTool?”
  • “What You Don’t know about sourceMap”

Optimization (Preface)

Whether a project needs to be optimized, according to their own project situation to decide. For example, certain optimizations are only useful for large projects, but can be counterproductive for small projects. If you feel your build speed and project size are acceptable, there is no need to optimize.

Here are some points that can be optimized, but don’t add them all. According to their own project situation to try and choose, view the effect

Optimize pre-preparation

speed-measure-webpack-pluginFor viewingloaderThe plug-inProcessing time of

webpack-bundle-analyzerUse to view the size of the package after packaging.

Reduced file search scope

Specifies the loader processing range ———— exclude/include

Exclude is to exclude from looking in a directory

Include is the limit to what directory to look in

If the value of exclude is configured, the priority of exclude is higher than that of include. You are advised to use include only.

// webpack.commom.js
{
	test: /\.js$/.// exclude: /node_modules/, 
	include: path.join(__dirname, ".. /src"),
	use: ["babel-loader"]},Copy the code

Resolve. alias Alias configuration

Use aliases instead, write more concise, can also play a role in reducing the scope of the search

// webpack.commom.js
resolve: {
	alias: {
		"@": path.join(__dirname, ".. /src")}},Copy the code

Resolw. extensions specifies the file suffix matching rule

Webpack is set to Extensions: [‘.js’, ‘.json’] by default, assuming the file is imported without a suffix, it will match this rule.

For example: import router from “@/router/index”, look for js first, then json.

Extensions can change the order of the match. You can jump to its priority. Files that are not commonly used are not recommended

// webpack.commom.js
  resolve: {
    extensions: [".js".".vue".".json"]
	/ / extensions: [", "js" ts ", "vue", "json"] if you have used to project ` typescript ` recommends `. Ts ` in front
  }
Copy the code

The cache

cache-loader

Cache-loader is used in front of some loaders with high overhead. Loaders with low overhead do not need to be used. It will cache the results to disk, node_modueles/.cache/cache-loader default directory. The first build will take longer, and later builds will be faster

npm install cache-loader -D
Copy the code
// webpack.commom.js

{
	test: /\.js$/,
	include: path.join(__dirname, ".. /src"),
	use: ["cache-loader"."babel-loader"]}Copy the code

babel-loader

In fact, Babel-Loader has its own caching function. I heard that cache-loader is a little faster. I have tried it myself and it is not much difference, cache-loader is slightly faster.

// webpack.commom.js
{
	test: /\.js$/,
	include: path.join(__dirname, ".. /src"),
	use: [{
		loader: 'babel-loader'.options: {
			cacheDirectory: true}}},Copy the code

hard-source-webpack-plugin

HardSourceWebpackPlugin provides an intermediate cache for modules that take normal time to build for the first time. The second build is 60% to 90% faster. Use of DllPlugin and DllReferencePlugin together is not recommended

Note: When using HardSourceWebpackPlugin, do not use speed-measure-webpack-plugin, which will cause an error

npm install hard-source-webpack-plugin -D
Copy the code
// webpack.commom.js

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

plugins: [
   	// Provides an intermediate cache for modules that cannot be used with the SpeedMeasurePlugin plug-in
	new HardSourceWebpackPlugin(),
	// Exclude the MiniCssExtractPlugin from caching, otherwise an error will be reported
	new HardSourceWebpackPlugin.ExcludeModulePlugin([
		{
			test: /mini-css-extract-plugin[\\/]dist[\\/]loader/,},]),]Copy the code

multithreading

As we all know that JavaScript is single-threaded, we can use Web Workers to execute JavaScript in real time with multiple threads. If you haven’t heard of the Web Worker, check out the article “Web Worker Tutorial”.

When building a project with WebPack, we can also use worker. There are two worker-based plug-ins, thread-Loader and happypack. Happypack seems to have been abandoned by the author, and thread-loader is recommended.

Please only use it on the loader that takes a long time!

npm install thread-loader -D
Copy the code
// webpack.commom.js

{
	test: /\.js$/,
	include: path.join(__dirname, ".. /src"),
	use: ["thread-loader"."cache-loader"."babel-loader"]
	// Loader takes a long time when the project is large
}
Copy the code

The compression

JS compression, remove comments andconsoleterser-webpack-plugin

Webpack 4 requires installation and WebPack 5 is supported by default

 npm i terser-webpack-plugin@4 -D
Copy the code
// webpack.prod.js

const TerserPlugin = require('terser-webpack-plugin');

optimization: {
	minimizer: [
		JS / / compression
		new TerserPlugin({
			parallel: true.// Enable multithreading
			// include: path.join(__dirname, ".. /src"),
			sourceMap: true.// Set this to true if SourceMapDevToolPlugin is used
			extractComments: false.// The default package will generate a LICENSE. TXT file, set here to disable the generation
			terserOptions: {
				output: {
					comments: false.// Delete comments
				},
				compress: {
					drop_console: true / / remove the console
					// drop_debugger: false // Default to true, debugger will be deleted},},}),],},Copy the code

CSS extract

If the generated JS package is too large, extracting CSS will help reduce the size of JS and render the page quickly (link introduces styles without blocking DOM and JS rendering).

NPM [email protected] - I DCopy the code
// webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
	rules: [{test: /\.(css)$/,
			include: path.join(__dirname, ".. /src"),
			use: [
				MiniCssExtractPlugin.loader,
				// "thread-loader", // if the project is large, the loader will take a long time to use
				"css-loader"."postcss-loader"] {},test: /\.(less)$/,
			include: path.join(__dirname, ".. /src"),
			use: [
				MiniCssExtractPlugin.loader,
				// "thread-loader", // if the project is large, the loader will take a long time to use
				"css-loader"."postcss-loader"."less-loader",]},]},/ / CSS

plugins: [
	new MiniCssExtractPlugin({
		filename: 'css/[name].[hash:8].css'}),]Copy the code

CSS compression

The goal is to reduce the volume of the project

npm i optimize-css-assets-webpack-plugin -D
Copy the code
// webpack.prod.js const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); Plugins: [// Compress CSS new OptimizeCssAssetsPlugin()]Copy the code

Reduce packaging

Tree Shaking

Tree Shaking is used to weed out code that was introduced but not used.

"SideEffects ": ["*.css", "*.vue"], "sideEffects": ["*.css", "*.vue"]Copy the code

externals

When packaging, eliminate these externals configured packages to reduce the volume. These packages are then introduced using a CDN.

  // webpack.prod.js
  externals: {
    "vue": "Vue"."vue-router":"VueRouter"	
  }
Copy the code
<! -- index.html -->
<! -- CDN introduces dependencies excluded by externals -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.runtime.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.5.2/vue-router.min.js"></script>
Copy the code

Rely on the version

As the latest version is WebPack 5, some plug-ins will also be updated synchronously, and the latest version of plug-ins is not applicable to WebPack 4, please refer to the following dependent version for installation!

  "devDependencies": {
    "@babel/core": "^ 7.4.4." "."@babel/preset-env": "^ 7.14.8"."autoprefixer": "^ 10.3.1"."babel-loader": "^ 8.2.2"."cache-loader": "^ 4.1.0." "."clean-webpack-plugin": "^ 3.0.0"."css-loader": "^ 5.2.7." "."file-loader": "^ 6.2.0"."hard-source-webpack-plugin": "^ 0.13.1." "."html-webpack-plugin": "^ 4.5.2." "."less": "^ 3.5.0." "."less-loader": "^ 7.3.0"."mini-css-extract-plugin": "^ 1.6.2"."optimize-css-assets-webpack-plugin": "^ the 6.0.1." "."postcss-loader": "^ 4.3.0"."speed-measure-webpack-plugin": "^ 1.5.0." "."style-loader": "^ 2.0.0." "."terser-webpack-plugin": "^ holdings"."thread-loader": "^ 3.0.4"."url-loader": "^ 4.4.1"."vue-loader": "^ 15.9.6"."vue-template-compiler": "^ 2.6.14"."webpack": "^ 4.46.0"."webpack-cli": "^ 3.3.11." "."webpack-dev-server": "^ 3.11.2"."webpack-merge": "^ 5.8.0"
  },
Copy the code

The article demo has been submitted to Github, please download ———— “Webpack 4 Demo”

Feel good remember “like”! thank you