Environmental analysis
The development environment
- In a development environment, We need a powerful Source Map (easy for developers to debug code) and a localhost Server (local server) with live reloading, hot Module replacement capabilities.
Roughly as follows:
- Webpack-dev-server real-time reload, hot replace
- Uncompressed code
- CSS styles are not extracted into separate files
- Map source code to raw files using sourceMap configuration (easy to debug)
- Don’t compress HTML
The production environment
- In the production environment, we shifted our focus to smaller bundles, lighter source maps, and more optimized resources to improve load times.
Roughly as follows:
- No need for real-time reloading, hot replacement
- Compressing JS and CSS
- CSS styles are extracted into separate files
- sourceMap.
- Optimization of code
- Compressed HTML
- Resource cache (NamedChunksPlugin, HashedModuleIdsPlugin)
- Clear the dist directory files
Resolving common code
In both environments, common configurations need to be merged, so the webpack-Merge merge tool is used to solve the problem of code duplication.
Install webpack – merge
npm i webpack-merge -D
Copy the code
Latest directory, files
Lesson # - 05 | - build | - webpack. Base. Conf., js / / + general configuration | - webpack. Dev. Conf., js / / + development environment configuration | - webpack. Prod. Conf. Js / / + Production | - node - modules | - public | - package. Json | - package - lock. Json | - SRC | - print. Js / / + is used to test the caching | - the favicon. Ico / / + Web page iconCopy the code
Install production environment packages
npm i cross-env copy-webpack-plugin mini-css-extract-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
Copy the code
- Cross-env: Configure environment variables on the command line (see package.json)
- Copy-webpack-plugin: copies resources
- Mini-css-extract-plugin: Extract to CSS file separately
- Optimize – CSS -assets-webpack-plugin: compress CSS files
- Uglifyjs-webpack-plugin: Compress JS files
General configuration
webpack.base.conf.js
const path = require('path')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const resolve = (dir) = > path.resolve(__dirname, dir)
const jsonToStr = (json) = > JSON.stringify(json)
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
// Entry configuration
entry: {
app: ['@babel/polyfill', resolve('.. /src/main.js')]},// Package the output configuration
output: {
path: resolve('.. /dist'),
filename: 'bundle.js' // Filename is generated relative to path
},
// Introduce resource ellipsis suffixes and resource alias configurations
resolve: {
extensions: ['.js'.'.json'.'.vue'].alias: {
The '@': resolve('.. /src')}},// Define module rules
module: {
rules: [{test: /\.jsx? $/.loader: 'babel-loader'.// Specify a directory to load the babel-loader to increase the speed of running and packaging
include: [resolve('.. /src'), resolve('.. /node_modules/webpack-dev-server/client')].// Remove the directory, improve the speed of operation, packaging
exclude: file= > (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
},
{
test: /\.(png|svg|jpg|gif)$/.loader: 'file-loader'.options: {
// Specify the generated directory
name: 'static/images/[name].[hash:7].[ext]',}}, {test: /\.vue$/.loader: 'vue-loader'}},// Plug-in options
plugins: [
// Define environment variables
new webpack.DefinePlugin({
'process.env.NODE_ENV': isProd ? jsonToStr('production') : jsonToStr('development')}),new VueLoaderPlugin()
]
}
Copy the code
Development Environment Configuration
webpack.dev.conf.js
const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const baseWebpack = require('./webpack.base.conf')
const resolve = (dir) = > path.resolve(__dirname, dir)
module.exports = merge(baseWebpack, {
mode: 'development'.devtool: 'cheap-source-map'.// Enable the cheap-source-map mode debugging
// Start the Web server and hot update
devServer: {
open: true.hot: true.port: 3002.publicPath: '/'.contentBase: resolve(".. /dist") // Set the dist directory to the contents of the server preview
},
// Define module rules
module: {
rules: [{test: /\.(css|scss|sass)$/.use: [{loader: 'style-loader'
},
{
loader: 'css-loader'.options: {
importLoaders: 1}}, {loader: 'sass-loader'.options: {
implementation: require('dart-sass')}}, {loader: 'postcss-loader'}]}]},// Plug-in options
plugins: [
// HTML template and related configuration
new HtmlWebpackPlugin({
title: 'Lesson-06'.template: resolve('.. /public/index.html')}),// Hotreplace plugin
new webpack.HotModuleReplacementPlugin(),
// The update file name is returned directly during hot loading, not the file ID.
new webpack.NamedModulesPlugin()
]
})
Copy the code
Production Environment Configuration
webpack.prod.conf.js
const path = require('path')
const merge = require('webpack-merge')
const webpack = require('webpack')
const webpackConfig = require('./webpack.base.conf')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const resolve = (dir) = > path.resolve(__dirname, dir)
module.exports = merge(webpackConfig, {
mode: 'production'.devtool: false.// Run and package the output configuration
output: {
path: resolve('.. /dist'),
filename: 'static/js/[name].[chunkhash:8].js'
},
// Compress js, CSS resources, and subcontract
optimization: {
splitChunks: {
chunks: 'all'.cacheGroups: {
libs: {
name: 'chunk-libs'.// The name of the js file generated after packaging
test: /[\\/]node_modules[\\/]/.priority: 10.chunks: 'initial' // Package only the third party that you originally relied on
},
// The elementUI option is not currently used (see configuration in elementUI)
elementUI: {
name: 'chunk-elementUI'.// Unpack elementUI separately
priority: 21.// The rights are more important than liBS and APP, otherwise they will be packaged into LIBS or APP
test: /[\\/]node_modules[\\/]element-ui[\\/]/
},
// The Commons option is not currently used (see elementUI configuration)
commons: {
name: 'chunk-commons'.test: resolve('.. /src/components'), // You can customize your rules
minChunks: 3.// Minimum public count
priority: 5.reuseExistingChunk: true}}},runtimeChunk: 'single'.minimizer: [ // Compress js and CSS configurations
new UglifyJsPlugin({
sourceMap: false.cache: true.parallel: true
}),
new OptimizeCSSAssetsPlugin()
]
},
// Define module rules
module: {
rules: [{test: /\.(scss|sass)$/.use: [{loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'.options: {
importLoaders: 2.sourceMap: false}}, {loader: 'sass-loader'.options: {
implementation: require('dart-sass'),
sourceMap: false}}, {loader: 'postcss-loader'.options: {
sourceMap: false}}]},]},// Plug-in options
plugins: [
// Clear the last build file based on the output export directory
new CleanWebpackPlugin(),
// Create an HTML entry without manually importing JS and CSS resources
new HtmlWebpackPlugin({
template: resolve('.. /public/index.html'),
title: 'Lesson-06'.favicon: resolve('.. /favicon.ico'),
HTML / / compression
minify: {
removeComments: true.collapseWhitespace: true.removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference}}),// Extract to a separate CSS file
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css'.chunkFilename: 'static/css/[name].[contenthash:8].css'
}),
// Copy resources
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '.. /public'),
to: path.resolve(__dirname, '.. /dist')}]),// Keep chunk.id stable when chunk has no name (cache chunk)
new webpack.NamedChunksPlugin(chunk= > {
if (chunk.name) {
return chunk.name
}
const modules = Array.from(chunk.modulesIterable)
if (modules.length > 1) {
const hash = require('hash-sum')
const joinedHash = hash(modules.map(m= > m.id).join('_'))
let len = 4
const seen = new Set(a)while (seen.has(joinedHash.substr(0, len))) len++
seen.add(joinedHash.substr(0, len))
return `chunk-${joinedHash.substr(0, len)}`
} else {
return modules[0].id
}
}),
// Keep module.id stable when the vender module does not change (cache vender)
new webpack.HashedModuleIdsPlugin()
]
})
Copy the code
Dynamic CDN resource configuration
In the process of referring to the configuration of others, I found a way to customize the CDN configuration in Webpack, mainly by using the ability of htML-webpack-plugin to add custom attributes and link CDN resources into the custom attributes. CDN resource imports are automatically generated by traversing attributes in the index. HTML template.
As follows:
Webpack. Dev. Conf. Js, webpack. Prod. Conf. Js
. omit// Plug-in options
plugins: [
// HTML template and related configuration
new HtmlWebpackPlugin({
title: 'Lesson-06'.template: resolve('.. /public/index.html'),
// CDN (custom attributes) loaded resources, do not need to manually add to index.html,
// The order is loaded by array index
cdn: {
css: ['https://cdn.bootcss.com/element-ui/2.8.2/theme-chalk/index.css'].js: [
'https://cdn.bootcss.com/vue/2.6.10/vue.min.js'.'https://cdn.bootcss.com/element-ui/2.8.2/index.js']}})]... omitCopy the code
public/index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title><% = htmlWebpackPlugin.options.title% ></title>
<! -- import cdn css -->
<% if(htmlWebpackPlugin.options.cdn) {% >
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>">
<%} % >
<%} % >
</head>
<body>
<div id="box"></div>
<! -- import cdn js -->
<% if(htmlWebpackPlugin.options.cdn) {% >
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%=js%>"></script>
<%} % >
<%} % >
</body>
</html>
Copy the code
Configure the development and production environment commands
Add dev and build commands to the scripts option of package.json.
package.json
{
"name": "lesson-06"."version": "1.0.0"."description": ""."main": "main.js"."scripts": {
"dev": "npx webpack-dev-server --config ./build/webpack.dev.conf.js"."build": "cross-env NODE_ENV=production npx webpack --config ./build/webpack.prod.conf.js"
},
"keywords": []."author": ""."license": "ISC"."devDependencies": {
"@babel/core": "^ 7.4.4." "."@babel/polyfill": "^ 7.4.4." "."@babel/preset-env": "^ 7.4.4." "."autoprefixer": "^ 9.5.1"."babel-loader": "^ 8.0.5"."clean-webpack-plugin": "^ 2.0.1." "."copy-webpack-plugin": "^ 5.0.3." "."cross-env": "^ 5.2.0." "."css-loader": "^ 2.1.1"."dart-sass": "^ 1.19.0"."file-loader": "^ 3.0.1." "."html-webpack-plugin": "^ 3.2.0"."mini-css-extract-plugin": "^ 0.6.0"."optimize-css-assets-webpack-plugin": "^ 5.0.1." "."postcss-loader": "^ 3.0.0"."sass-loader": "^ 7.1.0"."style-loader": "^ 0.23.1"."uglifyjs-webpack-plugin": "^ 2.1.2"."vue-loader": "^ 15.7.0"."vue-template-compiler": "^ 2.6.10"."webpack": "^ 4.30.0"."webpack-cli": "^ 3.3.0"."webpack-dev-server": "^ 3.3.1"."webpack-merge": "^ 2"
},
"dependencies": {
"vue": "^ 2.6.10"}}Copy the code
complete
After the configuration is complete, try running:
- The development environment
npm run dev
Copy the code
- The production environment
npm run build
Copy the code
If there are no problems, the local server is started, the production environment directory is generated, and the files (dist in the root directory) are generated. Otherwise, you can go to Github for clone project to view the source code, with comments.
The project address
Source address click on this GitHub