The original link: banggan. Making. IO / 2019/05/09 /…

Webpack core concept analysis

Finally finished the paper, can happily start to learn, pick up front-end crane, Webpack and Vue source code interpretation as a review before entry. The whole Webpack series will be divided into five major parts, with Webpack 4.0 as the document for interpretation, from simple concept interpretation to the final implementation. The whole knowledge point involves the scope:

loader

Use loader to preprocess files and package different static resources (modules whose modules don’t end in JS) into JS files

Loader packs static resources

Packaging pictures

  • Install using file-loader:npm install file-loader -D
  • Add loader configuration in webpack.config.js
Module.exports = {// Exports file entry:'./src/index.js',
    module:{
        rules:[{
            test: / \. (JPG | PNG | GIF) $/, / / packaging all ends in JPG, PNG, GIF image file use: {loader:'file-loader', options:{//placeholder name:'[name]_[hash].[ext]'// Keep the original image name +hashValues and suffixes, mainly single quotes outputPath:'image/'}}}}Copy the code
  • See the documentation for more information on the configuration of file-loader

Package the image into base64 format

Url-loader basically implements the file-loader packaging function, which is suitable for packing small images

  • Benefits: Images packaged into JS files, no need to load the image address, the page quickly display
  • Cons: Large images cause large JS files

Therefore, if the size of the image is smaller than the limit value, the image will be packed into base64 format, and if the size is larger than the limit value, the image will be packed into file file according to file-loader

  • Install using url-loader:npm install url-loader -D
  • Add loader configuration in webpack.config.js
Module. exports = {module:{rules:[{// package all image files that end in JPG, PNG, GIFtest:/\.(jpg|png|gif)$/,
            use:{
                loader:'url-loader', options:{//placeholder name:'[name]_[hash].[ext]'// Keep the original image name +hashValues and suffixes, mainly single quotes outputPath:'image/'// Where to pack the imagelimit:2048}}]}}Copy the code
  • See the documentation for more details on url-loader configuration

Package the style CSS file

Css-loader and style-loader are required

  • Css-loader: analyzes the relationship between several CSS files and merges them
  • Style-loader: Mount the combined CSS content in the head section of the page

Implementation method:

  • Install loader implementation:npm install css-loader style-loader -D
  • Add loader configuration in webpack.config.js
Module. exports = {module: {rules: [{// package CSS filestest:/\.css$/,
            use:['style-loader'.'css-loader']]}}}Copy the code
  • For more information about csS-Loader configuration, see the documentation

Package style SCSS files

Sass-loader and Node-sass are required

  • Install loader implementation:npm install sass-loader node-sass -D
  • Add loader configuration in webpack.config.js
module.exports = {
    module: {
        rules: [{
            test: /\.scss$/,
            use:['style-loader'.'css-loader'.'sass-loader']}}};Copy the code

In the configuration, there are three Loaders, executed from bottom to top and right to left. When packing SCSS files, execute sass-loader first: translate SASS into CSS files, mount them to CSS-loader, and then execute style-loader.

  • See the documentation for more details on the sas-Loader configuration

Add a different browser prefix to the style

In order to be compatible with different browsers, you need to add prefixes for different browsers when writing styles, such as -o, -webkit, and -moz

– NPM install postcss-loader autoprefixer -d – Create postcss.config.js in the root directory

moudle.exports ={
	plugins:[
        require('autoprefixer')]}Copy the code
  • Add loader configuration in webpack.config.js
module.exports = {
    module: {
        rules: [{
            test:/\.scss$/,
            use:[
            'style-loader'.'css-loader'.'sass-loader'.'postcss-loader']]}}}Copy the code
  • For more information about postCSS-Loader configuration, see the documentation

Css-loader adds different configurations

CSS Modular Packaging
  • Scenario: SCSS introduced in a file not only affects the current file, but also other JS files introduced in the current file, causing style conflicts
  • Implementation: CSS is only valid for the current module class, added in configurationmodules:trueEnable the modular packaging of the CSS
Nested references to SCSS files
  • Scenario: The SCSS file imports other SCSS files through import. As a result, the imported SCSS file is packaged incorrectly

  • Implementation: importLoader: 2

  • Add loader configuration in webpack.config.js

Module :{rules:[{// Package the SCSS filetest:/\.scss$/,
            use:[
            'style-loader',
            {
                loader:'css-loader', the options: {importLoaders: 2, / / index. By introducing other import of SCSS SCSS document, introduction of SCSS document at the time of packaging will, in turn, after all the loader modules:true}},'sass-loader'.'postcss-loader']]}}Copy the code

Package the font icon file

In alibaba vector icon library, the font icon needs to download to the local, decompress. Eot iconfont. SVG iconfont. TTF iconfont. Woff 4 image files into the project, create a new SRC folder font icon. Copy the iconfont. CSS file to the project and change the reference path of the corresponding font.

  • File-loader needs to be installed:npm i file-loader -D
  • Add loader configuration in webpack.config.js
module.exports = {
    ...
    module: {
        rules: [{
            test: /\.(eot|ttf|svg|woff)$/,
            use:{
                loader:'file-loader'}},]}]}}Copy the code
  • See the documentation for more on the configuration of loading fonts

Package data files

For example, cSV-loader and XML-loader are used to package JSON, SCV, and XML files.

  • NPM install csv-loader xml-loader -d
  • Add loader configuration in webpack.config.js
  module.exports = {
    module: {
      rules: [{
         test: /\.(csv|tsv)$/,
         use: [
           'csv-loader'] {},test: /\.xml$/,
         use: [
           'xml-loader']]}}}Copy the code
  • See the documentation for more configuration on loading data

plugins

Loaders can package various types of static resources into modules that WebPack can handle, while plugins are much more powerful. It can range from package optimization and compression to redefining variables in the environment.

Plugin can automatically do something when webPack is running at a certain point.

Automatically generates HTML files, and introduces packaged generated JS files into the generated HTML files

  • Install using HtmlWebpackPlugin:npm install html-webpack-plugin -D
  • Add loader configuration in webpack.config.js

Create an HTML template in SRC and import the template in the configuration of HtmlWebpackPlugin. After packaging, generate AN HTML file similar to the template and import the packaged JS file.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
    plugins: [new HtmlWebpackPlugin({
        template: 'src/index.html'}})]Copy the code
  • See the documentation for more information about the configuration of HtmlWebpackPlugin

Automatically clean up the last packaged dist file

Delete the last packaged dist file first, and then perform the packaging

  • Install using the CleanWebpackPlugin:npm install clean-webpack-plugin -D
  • Add loader configuration in webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');

module.exports = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
    plugins: [
        new HtmlWebpackPlugin({
        template: 'src/index.html' 
    }),
        new CleanWebpackPlugin(['dist']), // Delete all contents in dist folder before packing]}Copy the code
  • See the documentation for more information on the configuration of the CleanWebpackPlugin

Basic configuration of Entry and Output

  • Requirement: package multiple entry files, and ensure that each file has a unique name by naming filename to avoid export filename conflicts —- use placeholders
  • Requirement: The packaged file is used as the interface file of the backend. Static resources need to be uploaded to the CDN and configured in output. The ADDRESS of the CDN is added in advance. If the publicPath address is not known at compile time, it can be left blank and set dynamically when the entry start file is run.__webpack_public_path__ = myRuntimePublicPath
module.exports = {
	mode: 'development',
	entry: {
		main: './src/index.js',
		sub: './src/index.js'
	},
	plugins: [new HtmlWebpackPlugin({
		template: 'src/index.html'
	}), new CleanWebpackPlugin(['dist'])],
	output: {
		publicPath: 'http://cdn.com.cn'// add CDN address filename:'[name].js',
		path: path.resolve(__dirname, 'dist')}}Copy the code
  • See the documentation for more information on output configuration

SourceMap configuration

SourceMap is a mapping between packaged files and source files for developer debugging.

Set devtool: devtool: ‘source-map’ packaging speed will be slow, there will be a map file in dist

Devtool:

  • None: Sourcemap is turned off by default in developer mode
  • Inline prefix: instead of generating a map file separately, the corresponding map file is packaged directly into a JS file as base64.
  • Cheap prefix: Sourcemap and packaged JS counterparts are shown, and columns are not mapped to ignore the source from the Loader. Map, and only the translated code is displayed, so packaging is relatively fast. The code error prompt does not display the exact number of lines and characters in error, but only the number of lines in error, which can improve some performance.
  • Moudle prefix: maps not only business code, but also loader, third-party module errors.
  • Eval prefix: fastest packaging speed.

Devtool: ‘cheap-module-eval-source-map’

Devtool: ‘cheap-module-source-map’

  • More on devtool documentation

Use WebpackDevServer to improve development efficiency

Scenario: Every time you write code in SRC, you need to manually re-run the NPM run bundle.

– Install: NPM install webpack-dev-server -d

  • DevServer Parameter Description
  1. ContentBase: The root of the file that configures the development service runtime
  2. Open: Automatically opens the browser
  3. Host: indicates the host address monitored by the development server
  4. Compress: Indicates whether compression such as Gzip is enabled on the development server
  5. Port: the port listened by the development server
  • In webpack.config.js, add devServer
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
	mode: 'development',
	devtool: 'cheap-module-eval-source-map',
	devServer: {
		contentBase: './dist',
		open: true, port: 8080 proxy:{// If cross-domain configuration is configured, the accessed domain name will be proxy to port 3000'/api': 'http://localhost:3000'}}}Copy the code
  • Configure in package.json
{
  "name": "banggan"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "bundle": "webpack"."watch": "webpack --watch"."start": "webpack-dev-server",}}Copy the code
  • More on devServer documentation

How to write a similar webPackdevServer tool

  • Configure to create a new directive in package.json,npm run serverRun your own tools like WebPackDevServer
{
  "name": "banggan"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "bundle": "webpack"."watch": "webpack --watch"."start": "webpack-dev-server"."server" : "node server.js"}},Copy the code
  • Express installation:npm install express webpack-dev-middleware -D
  • Create a server.js file in the root directory
  • Use Webpack directly in Node:Webpack (config)
const express = require('express'); // introduce express const webpack = require('webpack'); Const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js'); Const complier = webpack(config); Const app = express(); App. use(webpackDevMiddleware(complier, {})); App.listen (3000, () => {// Listen to port 3000 console.log('server is running');
});
Copy the code

Hot Module Replacement Updates a Hot Module

  • Scenario: While the program is running. Replace, add, or replace a module without reloading the entire page.

  • In webpack.config.js, add the configuration

module.exports = {
	mode: 'development',
	devtool: 'cheap-module-eval-source-map',
	devServer: {
		contentBase: './dist',
		open: true,
		port: 8080,
		hot: true// Enable hot update function hotOnly:true}, plugins: [new HtmlWebpackPlugin({template:'src/index.html'
		}), 
		new CleanWebpackPlugin(['dist']), the new webpack. HotModuleReplacementPlugin using thermal module () / / plugins],}Copy the code
  • In the main. Js file, use HotModuleReplacementPlugin enable hot replacement function module. The interface is exposed under the moudle.hot property
// If the module has HMR enabled, you can use module.hot.accept() to listen for module updates.if (module.hot) {
  module.hot.accept('./library.js'.function() {// Perform some operations with the updated Library module... })}Copy the code
// Reject updates for a given dependency module, using'decline'Method failed to force an update. Module.hot. Decline (dependencies)Copy the code

Note: Module.hot.accept () is not needed when introducing CSS files using framework Vue, React, because CSS-loader, VUe-loader, babel-loader, are all configured with HMR, and there is no need to preset. You need to manually write the listening module update code

ES6 syntax with Bable

  • Scenario: The code contains ES6/ES7 code and needs to be converted using Bable in order to make the code compatible with older browsers
  • Installation :Bable official website
// Preset -env NPM install babel-loader @babel/ core@babel /preset-env -d // Compatible with earlier versions of browsers, NPM install --save @babel/polyfillCopy the code
  • In webpack.config.js, add the configuration
module: {
  rules: [
    {
        test: /\.js$/, exclude: /node_modules/, // exclude: /node_modules/"babel-loader" ,
        options:{
            "presets": [["@babel/preset-env",{
                targets: {
                    edge: "17",
                    firefox: "60",
                    chrome: "67",
                    safari: "11.1"},// High browsers that already support ES6 do not need to convert to ES5 useBuiltIns when running on browsers older than ** :'usage'// Add polyfill as needed to convert new syntax and functions in business code to lower browser compatible}]]}}]}Copy the code
  • Import it at the top of index.js in the SRC directoryimport "@babel/polyfill";

Note that you should not use @babel/polyfill if you are writing a class library or z component library instead of packing business code, as this will cause declared variables to become global variables and pollute the global environment. Use plugin-transform-Runtime

  • Installing a plug-in
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2

Copy the code
  • In webpack.config.js, add the configuration
module: {
  rules: [
    {
        test: /\.js$/,
     	exclude: /node_modules/,
     	loader: "babel-loader" ,
        options:{
            "plugins": [["@babel/plugin-transform-runtime", {"corejs": 2."helpers": true."regenerator": true."useESModules": false}]}}]}Copy the code

Because Babel configuration contains a lot of information, you are advised to create a. Babelrc configuration file in the root directory

Because Babel needs to be configured so much, we need to create a.babelrc file in the project root directory. There is no need to write the configuration of Babel in webpack.config.js. In the babelrc:

{
	"plugins": [["@babel/plugin-transform-runtime", {
		"corejs": 2."helpers": true."regenerator": true."useESModules": false}}]]Copy the code

conclusion

  • In webpack. Config. Js
module.exports = {
	mode: 'development'// Devtool is packaged in the development environment. The packaged code does not compress devtool:'cheap-module-eval-source-map',// No column information, only business code sourcemap generation entry: {// configure entry file main:'./src/index.js'}, devServer: {// configure webpack, development environment debugging contentBase:'./dist'// Start the server directory open:true// Open a new port 8080 port: 8080, hot:true// Enable hotreplace hotOnly:true}, module: {// How to package different filestest/\.js$/, // Exclude: /\.js$/ /node_modules/, // exclude: js in node_modules, babel-loader does not take effect loader:'babel-loader'}, {test: / \. (JPG | PNG | GIF) $/, / / packaging use images: {loader:'url-loader',
				options: {
					name: '[name]_[hash].[ext]',
					outputPath: 'images/'.limit: 10240// Less than 10240 is packaged as base64}}}, {test: / \. (eot | the vera.ttf | SVG) $/, / / font file packaging use: {loader:'file-loader'}}, {test: /\. SCSS $/,// SCSS file is packaged with postcss-loader, and then is parsed with sass-loader. Use: ['style-loader', 
				{
					loader: 'css-loader',
					options: {
						importLoaders: 2
					}
				},
				'sass-loader'.'postcss-loader'] {},test: /\.css$/,// CSS file packing, no sas-loader parsing use: ['style-loader'.'css-loader'.'postcss-loader'
			]
		}]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: 'src/index.html'
		}), 
		new CleanWebpackPlugin(['dist']), / / packaging automatic emptying the last new webpack HotModuleReplacementPlugin () / / hot replacement plugin], the output: {/ / export file filename:'[name].js',
		path: path.resolve(__dirname, 'dist')}}Copy the code