Learning notes, introductory level, understand the basic configuration of Webpack, single-page CSS \js\ HTML \ image resources involved in loader, plugins configuration. This section practices code. There will be continuous updates in the future. The goal is to systematically learn Webpack and achieve independent handwritten configuration of small and medium-sized projects.
Webpack installation
Environmental preparation:
- Install Node. The new version of Node comes with NPM
- Create a new project folder (e.g. Demo)
- perform
npm init
NPM init generates a pakeage.json file that records project information.
Install webpack
- npm install webpack –save-dev
- npm install webpack-cli –save-dev
- In the package. The json
"scripts": {
"webpack": "webpack"
},
Copy the code
- NPM run webpack -v, see the version number, that is, success
In WebPack 3, WebPack itself and its CLI used to be in the same package, but in version 4, they have separated the two to better manage them, so both packages need to be installed at the same time.
In this example, there is no global installation (–save-dev is replaced with -g), so webpack -v cannot be executed. Instead, an “NPM script” is used, which can also be implemented by configuring the computer’s path.
Webpack it based on the entry file, find the relevant dependencies, packaged into a file, packaged JS files can be directly run in the browser
Webpack can be packaged with 0 configuration
- Create folder SRC and create index.js
- npm run webpack
SRC /index.js in the same directory is packaged by default
Webpack zero configuration has low flexibility, so let’s go to manual configuration
Manual configuration, webpack.config.js
The default configuration that webpack reads is webpack.config.js.
-
npm run webpack –config webpack.config.my.js
-
Package. json Configuration script scripts
{
"scripts": {
"dev": "webpack --config webpack.config.js"},... }Copy the code
Basic configuration – Package JS
The packaged file is parsed roughly: an object with the module path as the key and the file contents as the value is passed to a self-executing __webpack_require__ function
/ * * * * * * /function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ returnmodule.exports; / * * * * * *}Copy the code
// Webpack is written by nodelet path = require('path'Module. Exports = {mode: node exports = {mode: node exports = {mode: node exports'production'// Production mode development mode entry:'./src/index.js'Output: {filename:'bundle.js'// filename:'bundle.[hash:8].js', / /hash:8 displays only 8 bits. If the file does not change,hashThe same path: the path. The resolve (__dirname,'dist'// __dirname uses the current path as the primary directory}}Copy the code
When mode=production, the js package is compressed
Local service
Currently we can only manually run files to the browser,webpack-dev-server can automatically access our project in the browser by loaclhost
Lead to
- Create a new index.html file under SRC
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
Copy the code
Configuration, added to webpack-config.js
DevServer: {port: 3000, // Default port: 8080 progress:true// You can see the service progress contentBase:'./dist'// Default access to the root directory},Copy the code
Webpack – dev – server installation
npm install webpack-dev-server --save-dev
Copy the code
The service
npx webpack-dev-server
Copy the code
Dist: : localhost:3000 is the default access to our project dist, but we do not put SRC index.html nor dist, so we need another plugin html-webpack-plugin
If the installation fails and a JSON error is reported, you can use NPM cache clean –force
HTML pluginhtml-webpack-plugin
What we want is to be able to automatically create HTML in dist and package it into memory, i.e. insert the packed JS file into SRC /index.html and generate the result in dist/index.html
HTML – webpack – the plugin installation
npm install html-webpack-plugin --save-dev
Copy the code
configuration
Add to webpack.config.js
// webpack.config.js
let HtmlWebpackPlugin = require('html-webpack-plugin')
plugins:[
new HtmlWebpackPlugin({
template: "./src/index.html"// Package template entry address filename:"index.html"// Get the file entry name after packinghash: true,
minify: {
removeAttributeQuotes:true// collapseWhitespace:true}})], // Delete space to make a line}})]Copy the code
Packaging HTML
In package. Jon scripts, add “build:”:”webpack”
npm run build
Copy the code
As a result, index.html is generated in the dist directory
css – loader
Loader enables WebPack to handle different files. Loader can convert all types of files into valid modules that WebPack can handle. Loader doesn’t just deal with CSS. Loader is executed from bottom to top and from left to right
Lodaer has two purposes
- Identify the files that should be converted by the corresponding loader. (Use the test attribute)
- Transform these files so that they can be added to the dependency diagram (and eventually to the bundle). (Use attribute)
Documents to prepare
- New SRC/a.c ss
- New SRC/index. The CSS
@import './a.css';
body {
color: red;
}
Copy the code
- In the index. Js added
require('./index.css')
At this point, your service will report an error saying “Need loader to handle this type of file”.
Loader configuration
- Style – loader: handle the import
- Css-loader: When running a service, the CSS is directly inserted into the HEAD of the HTML. Packaging does not take effect
- Postcss-loader autoprefixer: adds the prefix of compatible browsers to the CSS
Installation:
npm install style-loader css-loader postcss-loader autoprefixer --save-dev
Copy the code
module: {
rules: [
{
test: /\.css$/,
use: [
{loader: "style-loader"}, // When running the service, insert the CSS directly into the HEAD of the HTML, packaging will not take effect {loader:"css-loader"}, // handle import {loader:"postcss-loader"},]}]}Copy the code
In addition to adding loader to module,
- Create postcss.config.js in the root directory
// postcss.config.js
module.exports = {
plugins:[
require("autoprefixer")]}Copy the code
You will find
- The style was successfully inserted into the local service
- But say good
CSS adds the prefix of compatible browser
Does not work, need to change modeprodutiion
- After packing, there is no CSS in dist, that is because style-loader does not have this processing capability, so it needs
mini-css-extract-plugin
CSS generates an external file plug-in mini-CSS-extract-plugin
Can replace style-loader directly
The installation
npm install mini-css-extract-plugin --save-dev
Copy the code
Configuration, instead of style.loader
// webpack.config.js
let MiniCssExtractPlugin = require('mini-css-extract-plugin')
plugins:[
...
new MiniCssExtractPlugin({
filename: 'main.css'})] module: {rules:[{test:/\.css/,
use:[
MiniCssExtractPlugin.loader,
'css-loader'// parse @import]}... ] }Copy the code
Package + re-brush service, you will see
- CSS exchaining inserts into HTML
- After packaging, index.css is generated
- But if you open main.css, you’ll see that there’s no compression, and that’s what you need
optimize-css-assets-webpack-plugin
Compressing CSS Filesoptimize-css-assets-webpack-plugin
The installation
npm install optimize-css-assets-webpack-plugin --save-dev
Copy the code
configuration
let OptimizeCss = require('optimize-css-assets-webpack-plugin')
...
optimization: {
minimizer: [
new OptimizeCSS()
]
}
Copy the code
Optimize - CSS-assets-webpack-plugin will disable js compression by default and require manual plugin compression
Compression jsuglifyjs-webpack-plugin
- The installation
cnpm install uglifyjs-webpack-plugin --save-dev
Copy the code
- configuration
// webpack-config.js
let UglifyWebpackPlugin = require('uglifyjs-webpack-plugin')... optimization: { minimizer: [ ... new UglufyjsWebapckPlugin({ cache:true.sourceMap: true,
parallel: true}})]Copy the code
Es6 syntax conversion
- Babel – loader: turn es5 es6
- @babel/preset-env: Use the latest JS, pack the smallest JS, and preset browser can be specified
- @babel/plugin-proposal-decorators: @log syntax
- Babel /plugin-proposal-class-properties: ES7 syntax Advanced syntax
- Babel /plugin-transform-runtime: Unpack public methods
- Babel/Runtime: Production environment required
Document preparation:
// Add code @ to jslog
class A {
a = 1
}
let a = new A()
console.log(a.a)
function log(target) {console.log(target, 23)} var testprofill = [3,3,5] console.log(testprofill.includes(4))Copy the code
The installation
npm install babel-loader @babel/core --save-dev
Copy the code
npm install @babel/preset-env @babel/plugin-proposal-decorators --save-dev
Copy the code
npm install @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime --save-dev
Copy the code
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'babel-loader', // es6 to es5 options: {presets: ['@babel/preset-env'], // Use the latest js, package the smallest JS, and can specify the browser // plugins: ['@babel/plugin-proposal-class-properties', {"loose":true},
// '@babel/plugin-transform-runtime'// plugins: [['@babel/plugin-proposal-decorators', { 'legacy': true/ / @}]logGrammar ['@babel/plugin-proposal-class-properties', { "loose" : true}], // es7 syntax ['@babel/plugin-transform-runtime'],// Remove the package public method'/ / /'@babel/runtime'] / / production environment need to]}}], include: path. The resolve (__dirname, 'src// exclude: /node-modules/}]}Copy the code
For js processing, see Babel
Global variable introduction problem
Such as jquery, installation
npm install jquery --save-dev
Copy the code
There are three ways to introduce modules:
1. Expose the expose-loader to Windows
- The installation
npm install expose-loader --save-dev
Copy the code
- configuration
// webpack.config.js
module: {
rules:[
{
test: require.resolve('juery'),
use: [
{
loader: 'expose-loader', // es6 to es5 options: {option:'$'}}] or use:'expose-loader? $'
}
]
}
// index.js
import $ from 'jquery'
console.log($)
consle.log(window.$)
Copy the code
- ProviderPlugin provides each person with a $configuration
// webpack.config.js // introduces the webpack modulelet webpack = require('webpack')... plugins:[ new webpack.ProviderPlugin({ $:'jquery'.'jquery': 'jquery'})]Copy the code
- The script tag is imported without packaging the externals configuration
// webpack.config.js
externals: {
jquery: "$"} // The page is manually moved to js <script SRC ="XXX"></script> // js import $from jqueryCopy the code
Image packaging
- Add a new image in SRC, 1.jpg
- Create an image in JS to introduce
// index.js
let image = new Img();
image.src = './1.jpp'
document.body.appendChild(image)
Copy the code
If the service is running, an error is also reported. In this case, file-loader is required
File-loader can handle images imported from JS/CSS
npm install file-loader --save-dev
Copy the code
configuration
// webpack.config.js
{
test: /\.(png|jpe? g|gif)$/i, use: { loader:'file-loader',}},Copy the code
- Introduce images in CSS
// index.css
body {
color: red;
background: url("./1.jpg") no-repeat;
}
Copy the code
HTML – withimg – loaser installation
npm install html-withimg-loader --save-dev
Copy the code
configuration
// webapck.config.js
{
test:/\.html$/,
use: [
{
loader: 'html-withimg-loader'}}]Copy the code
Repackage and you’ll notice that the HTML image is still not displayed, but SRC is still changed./1.jpg is an object with default.
<img src='{"default":"5aae522a0485ba2405faad74163971a5.jpg"}' />
Copy the code
Just add esMoudle:true to the configuration of the Lie-loader
Install the url – loader
npm install url-loader --save-dev
Copy the code
configuration
Url-loader Is compressed into base64 based on the limit specified in options. If the value exceeds the limit, use file-loader to comment out file-loader
// add {to module.exports-module-rules}test: /\.(png|jpe? g|gif)$/i, use: { loader:'url-loader',
options: {
esModule: false.limit: 1// 200kb
}
}
},
Copy the code
Currently, the packaged files are placed directly under SRC. If you want CSS /image, put it in a separate folder
File sorting and packing
Image: Add outputPath to urL-loader configuration
/ / in {test: /\.(png|jpe? g|gif)$/i, use: { loader:'url-loader',
options: {
outputPath: '/img/'Dist /img... }}},Copy the code
CSS: Add the filename before filename of the mini-CSs-extract-plugin
new MiniCssExtractPlugin({
filename: 'css/main.css', // CSS extract to filename})Copy the code
The result of packing
Finally, really finally
Add an ESLint validation, which is a bit important for code specification, team collaboration, and not having to artificially follow the specification
eslint-loader
The installation
npm install eslint-loader --save-dev
Copy the code
configuration
We said the loader executes from bottom to top, but what if I write it first, but it needs the first checkout run
Enforce: ‘Pre’ says it’s time to show strength
{
test: /\.js$/,
use: {
loader: "eslint-loader",
options: {
enforce: 'pre'}}, include: path.resolve(__dirname,'src'),
exclude: /node_modules/
},
Copy the code
That’s not all. You need to create a.eslintrc.json file in the project root directory. Note the “.” in front of the file name.
// .eslintrc.json
{
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "script"."ecmaFeatures": {}},"rules": {
"constructor-super": 2."for-direction": 2,},"env": {}}Copy the code
Or you might ask, how do the rules know how to write them?
You can go to esLint, check the configuration you want, and download.eslintrc.json. You still need to know the rules for the validation items.
Multiple entry packing
JS multi-entry packaging
Documents to prepare
- SRC create index.js and other.js. The content is optional.
- New webpack. Config. Js
let path = require('path')
module.exports = {
mode: "development"// multientry single entry is the string './ SRC /index.js' entry: {home:'./src/index.js',
other: './src/other.js'
},
output: {
filename: 'bundle.js'Path: path.resolve(__dirname,'dist')}}Copy the code
packaging
Change filename configuration of output to [name].js, after packaging, there will be the corresponding JS
let path = require('path')
module.exports = {
mode: "development"// multientry single entry is the string './ SRC /index.js' entry: {home:'./src/index.js',
other: './src/other.js'
},
output: {
filename: '[name].js'Path: path.resolve(__dirname,'dist')}}Copy the code
HTML multi-entry packaging
Documents to prepare
- SRC create index. HTML and other. HTML
// index.html, other.html <! DOCTYPE html> <html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
hello world! webpack 12
</body>
</html>
Copy the code
configuration
Here we are wondering, can we introduce the HTML-webpack-plugin twice
let path = require('path')
let htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
...
plugin: [
new htmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
}),
new htmlWebpackPlugin({
template: './src/other.html',
filename: 'other.html']}}),Copy the code
packaging
chunks
. module.exports = { ... plugins: [ new htmlWebpackPlugin({ template:'./src/index.html',
filename: 'home.html',
chunks: ['home'}), new htmlWebpackPlugin({template:'./src/other.html',
filename: 'other.html',
chunks: ['other'.'home'] // Configure the introduction of multiple js}),]}Copy the code
To configure the source – the map
When the code in the development version is not exactly the same as the code running online, the Source Map technology can be used to facilitate debugging and locate the problem.
The type of devtool value
1) source-map: source code map, which will generate a separate sourcemap file, localization can be fixed to rows and columns, the code is the same as the source code.
4) Cheap -module-eval-source-map: no separate file is generated, positioning can only locate lines.
Documents to prepare
Delete multiple entries and run single pages
configuration
let path = require('path')
let htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: "production"// SRC /index.js' entry: {index:'./src/index.js',
},
output: {
filename: '[name].js'Path: path.resolve(__dirname,'dist')
},
devtool:'source-map'Plugins: [new htmlWebpackPlugin({template:'./src/index.html',
filename: 'index.html',
chunks: ['index']
}),
],
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'}}}]}}Copy the code
If source-map is not added, the code in the browser is packaged
The use of the watch
module.exports = {
watch: true, // Monitor changes watchOptions: {poll: 1000, // Monitor several times per second aggregateTimeout: Ignored :/node_modules/ / don't monitor files},}Copy the code
The application of the Webpack widget
- CleanWebpackPlugin files in the output.path path will be deleted, 4.0+ default, no need to write path details
- CopyWebpackPlugin copies files/folders to the specified folder
- The bannerPlugin webpack internal plug-in does not need to be reinstalled, and basically packs a comment into all the packaged files
The installation
npm install copy-webpack-plugin clean-webpack-plugin --save-dev
Copy the code
configuration
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
let copyWebpackPlugin = require('copy-webpack-plugin')
let webpack = require('webpack'Module.exports = {plugins:[... new CleanWebpackPlugin(), // Default to clean output.path new copyWebpackPlugin({patterns: [ {from:'doc', to: '/'}
]
}),
new webpack.BannerPlugin('2020') // All packaged files will be preceded by a 2020 comment]Copy the code
Webpack cross domain issues
1) Rewrite the way to proxy the request to express server, such as localhost:8080 request localhost:3000 interface
Documents to prepare
The new server. Js
let express = require('express'Var app = new express() //'/user', (req, res) => {
res.json({'name': 'hui lin4545? '})
})
app.listen(3000)
Copy the code
// index.js var XML = new XMLHttpRequest()'GET'.'/api/user'.true)
xml.onload = function() {
console.log(xml.response)
}
xml.send()
Copy the code
In this case, the cross-domain situation will occur, and the data cannot be requested, so the proxy needs to be configured
configuration
module.exports = {
devserver: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {'/api': ' '} // Request at the beginning of the unified control API}}}}Copy the code
You can see that the page can get data across domains
// server.js
app.get('/api/user', (req, res)=>{
res.json({name: 'hui lin4545'})
})
// index.js
xhr.open('GET'.'/api/user'.true)
// webpack.config.js
devServer: {
proxy: {
'/api': 'http://localhost:3000/'// the interface at the beginning of the API, all request http://localhost:3000/}},Copy the code
2) Pure simulation data, directly in the configuration of webpack simulation interface
configuration
devServer: {
before(app) {
app.get('/api/user',() = >(req, res){
res.json({name: 'hui lin-before'}}})})Copy the code
3) Directly start Webpack on the server side, there will be no cross-domain problems
The installation
npm install webpack-dev-middleware --save-dev
Copy the code
let express = require('express')
let app = new express()
let webpack = require('webpack')
let webpackDevMiddleWare = require('webpack-dev-middleware')
let config = require('./webpack.config.js')
let compiler = webpack(config)
app.use(webpackDevMiddleWare(compiler))
app.get('/api/user', (req, res)=>{
res.json({name: 'hui lin4545'})
})
app.listen(3000)
Copy the code
resolve
Parse the third-party package Common
If we directly import ‘boostrap’, with no suffix, it directly to find, in the node_modules node_modules/boostrap/package. The json/main values
- If we just want to introduce alone boostrap. CSS import ‘bootstrap/dist/CSS/bootstrap CSS’, will be add to the alias
module.exports = {
resolve: {
modules: [path.resolve('node_modulse')].alias: {// Add alias boostrap:'bootstrap/dist/css/bootstrap.css'}, mainFields:'style, main'Json main mainFiles: [], // specify the import file, default is index.js extensions: ['.js'.'.css'.'.json'}}}}}}}}}}}Copy the code
Defining environment variables
Webpack.defineplugin differentiates the current environment in your code
module.exports = {
plugins: [
new webpack.DefinePlugin({
DEV: '"production"'
DEV2: JSON.stringify('production'), // string FLAG:'true', // Boolean type EXT:'1 + 1'// expression})]} // index.jsif (DEV) console.log(DEV)
Copy the code
Distinguish between different environments
Merge files using webpack-merge
The installation
npm install webpack-merge --save-dev
Copy the code
configuration
// webpack.prod.js
let {smart} = require('webpack-merge')
let base = require('webpack.base.js')
module.exports = smart(base, {
mode: 'production'
})
Copy the code
Put the common ones in webpack.base.js, and you can configure different config files depending on your development and production environments