webpack learning notes

Keywords: Webpack

1, What are the main links in the Webpack construction process? If you can, please describe the whole process of Webpack packaging in as much detail as possible

1. Initialization item, initialization parameters: according to different parameters configured by the user
2. Initialization parameters. The final configuration is obtained according to the parameters entered by the user in the command window and the configuration of webpack.config.js
3. Start compiling, initialize a compiler object according to the last configuration parameters obtained in the previous step, register all plug-in plugin s, and the plug-in starts listening to the construction process of webpack,
Different links will correspond to the corresponding processing, and then start compiling.
3. Determine the entry. According to the entry entry in webpack.config.js, start parsing the file, build the AST syntax tree, and find out the dependencies.
4. The compilation module, in the recursive process, calls the corresponding loader to perform different conversion processing on different files according to the file type and loader configuration. Then find out the modules that the module depends on,
Until all the modules that the project depends on have been compiled
5. After compiling and outputting and recursion, get the results of each file, including the converted modules and their dependencies, and generate code blocks according to the configuration of entry and output,
The dist directory will be clear before the end.
6. After packaging, output to the specified directory according to output.

2. What are the differences between Loader and Plugin? Please describe the idea of developing Loader and Plugin.

1, Loader is directly translated as "loader", which is mainly used to parse and detect the corresponding resources and is responsible for the conversion of source files from input to output. It focuses on the loading of resource modules.
Handle some codes that are not supported or compatible with the browser as resources that the browser can support. For example, convert ES6 + to ES5 and Sass recognized by the browser to css.
1. Export a function through moudule.exports
2. The default parameter of this function is the first parameter source (i.e. the resource file to be processed)
3. Process resources in the function body (after the Loder of the response is configured in the Loder)
4. Return the last packaged result through return (the returned result here needs to be in string format)

2, Plugin mainly performs some additional work at different stages of webpack construction, such as copying static resources, emptying packaged folders, etc.
1. Through hook mechanism
2. The plug-in must be a function or an object containing an apply method
3. In the method body, obtain resources through the API provided by webpack for response processing
4. Return the processed resource to the resource through the method provided by webpack

## webpack.common.js

// const path = require('path')
const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')  // Packaging is the automatic creation of html
const TerserPlugin = require("terser-webpack-plugin")  // Code splitting, loading and packaging to remove unnecessary files
const { merge } = require('webpack-merge')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

// time analysis
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()

// Import other configurations
const prodConfig = require('./webpack.dev')
const devConfig = require('./webpack.dev')

// Define object to save base configuration information
const commonConfig = {
	entry: './src/main.js',  // Compile target resource file
	devtool: 'source-map',  // Code mapping, locating the error location
	// The inline column reports an error, and the soap improves efficiency by removing empty rows. The original soap module is restored.
	resolve: {
		extensions: [".js", ".json", ".ts", ".jsx", ".vue"],  // Match the path after the route and omit the file format suffix
		alias: {
			// '@': path. Resolve (_dirname, '.. / SRC') / / matches the path after the route, omitting the path before the path/
			'@': resolveApp('./src')
		}
	},
	output: {
		filename: 'js/build.js', // Output the file name and put it separately in the js directory
		// filename: 'js/[name].build.js', / / code splitting and packaging, dynamic file name
		// Path. Resolve (_dirname, '.. / dist'), / / output folder
		path: resolveApp('./dist'),
		publicPath: '/lg'  // Relative path or absolute path, address directory
	},
	externals: {  // Introducing CDN
		lodash: '_'  //  Naming after introduction
	},
	optimization: {
		minimizer: [
			new TerserPlugin({
				extractComments: false,
			}),
		],
		splitChunks: {
			chunks: 'all',  // Support asynchronous and synchronous all
			minSize: 20000,  // file size
			maxSize: 20000,
			minChunks: 1,
			cacheGroups: {
				syVendors: {
					test: /[\\/]node_modules[\\/]/,
					filename: 'js/[id]_vendor.js',  // filename can be dynamic, and name can only be written to death
					priority: -10,
				},
				default: {  // Number of visits
					minChunks: 2,
					filename: 'js/syy_[id].js',
					priority: -20,
				}
			}
		}
	},
	module: {  // Resource module
		rules: [  // rule
			{
				test: /\.css$/,
				use: [
					'style-loader',
					{
						loader: 'css-loader',
						options: {
							// The postcss loader does not check the code that needs to be compatible. If it is checked by CSS loader, you can go back one step
							importLoaders: 1
						}
					},
					{
						loader: 'postcss-loader',  // js conversion style tool. You need to install postcss and postcss cli
						options: {  // configuration parameter
							postcssOptions: {
								plugins: [  // Required plug-ins
									require('autoprefixer'),
									require('postcss-preset-env')  // Handle css compatibility issues, including autoprefixer
								]
							}
						}
					},
					{
						test: /\.(png|svg|gif|jpe?g)$/,  // Processing pictures
						// use: [
						// 	{
						// 		loader: 'file-loader',
						// 		options: {
						// 			name: 'img/[name].[hash:6].[ext]', / / specify the path and name for the picture (path / name. Hasi 6 bits. Suffix)
						// 			limit: 25 * 1024 / / picture size
						// 		}
						// 	}
						// ]
						type: 'asset',
						generator: {
							filename: 'img/[name].[hash:6].[ext]'
						},
						parser: {  // analysis
							dataUrlCondition: {
								maxSize: 30 * 1024
							}
						}
					},
					{
						test: /\.(ttf|woff2?)$/,  // Processing fonts
						type: 'asset/resource',
						generator: {
							filename: 'font/[name].[hash:3][ext]'
						}
					}
				]
			},
			{
				test: /\.less$/,
				use: [
					'style-loader',
					'css-loader',
					'postcss-loader',  // The principle is the same as above, and the postcss loader file is called externally
					'less-loader'
				]
			},
			{
				test: /\.js$/,  // Use bable loader to convert es6 syntax
				use: ['bable-loader']
			},
			{
				test: /\.jsx?$/,  // react hot update
				use: ['babel-loader']
			},
			{
				test: /\.vue$/, // vue hot update
				use: ['vue-loader']
			},
			{
				test: /\.ts$/,
				use: ['bable-loader']
			},
			{
				test: /\.css$/,  // Pull off css
				use: [
					isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
					{
						loader: 'css-loader',
						options: {
							importLoaders: 1,
							esModule: false
						}
					},
					'postcss-loader'
				]
			},
		]
	},
	plugins: [  // plug-in unit
		new HtmlWebpackPlugin({
			title: 'html-webpack-plugin',  // html internal title
			template: './public/index.html'  // html template path
		})
	]
}

module.exports = (env) => {
	const isProduction = env.Production

	process.env.NODE_ENV = isProduction ? 'prodConfig' : 'development'

	// Merge configurations according to the current packaging mode
	const config = isProduction ? prodConfig : devConfig

	const mergeConfig = merge(commonConfig, config)

	return mergeConfig

	return smp.wrap(mergeConfig)
}



## webpack.dev.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
   mode: 'development', // development environment 
   devtool: 'cheap-module-source-map',  // Code mapping, locating the error location
   // When an error is reported in the inline column, the soap improves efficiency and removes empty rows. The original soap module is restored.
   target: 'web',  // Mask browser compatibility
   devServer: {  // The configuration related to webpack dev serve is written here
       hot: true,  // Turn on hot update
       publicPath: '/lg',  // Consistent with the publicPath in output, find the resource target
       contentBase: path.resolve(__dirname, 'public'),
       watchContentBase: true,
       hotOnly: true,  // Error message before refresh (one component is not affected by other components)
       port: 4000,  // port
       open: false,  // Open a new page
       compress: true,  // Compress the current file
       historyApiFallback: true,  // Route switching 404
       proxy: {  // Solve cross domain
           '/api': {
               target: 'https://api.github.com ', / / ask who wants
               pathRewrite: { "^/api": "" },
               changeOrigin: true
           }
       }
   },
   plugins: [  // plug-in unit
 	  new VueLoaderPlugin()
   ]
}



## Title webpack.prod

const { CleanWebpackPlugin } = require('clean-webpack-plugin')  // Clear dist plug-in
const CopyWebpackPlugin = require('copy-webpack-plugin')  // Copy
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const TerserPlugin = require("terser-webpack-plugin")  // Compress js
// const webpack = require('webpack')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const resolveApp = require('./paths')
const glob = require('glob')
const CompressionPlugin = require("compression-webpack-plugin")  // Compressed resources
const InlineChunkHtmlPlugin = require('inline-chunk-html-plugin')  // Inject js code
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
	mode: 'production', // production environment 
	optimization: {
		// usedExports: true, / / mark code execution (Mark unused content in the code)
    	minimize: true,
		minimizer: [
			new CssMinimizerPlugin(),
			new TerserPlugin({
				extractComments: false
			})
		]
	},
	plugins: [  // plug-in unit
		new CleanWebpackPlugin(),  // Clear dist
		new CopyWebpackPlugin({
			patterns: [  // 
				{
					from: 'public',  // Where to start the copy, the target directory. You can omit to and find the path directory under output by default
					globOptions: {  // Ignore something
						ignore: ['**/index.html']  //  **/Indicates to search from public
					}
				}
			]
		}),
		// new webpack.optimize.ModuleConcatenationPlugin()
		new PurgeCSSPlugin({
			paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),  // Keep files and remove directories
			safelist: function () {
			  return {
				standard: ['body', 'html', 'ef']
			  }
			}
		}),
		new CompressionPlugin({
			test: /\.(css|js)$/,
			minRatio: 0.8,
			threshold: 0,  // Compression starts when the volume is greater than 0
			algorithm: 'gzip'  // Browser supported compression algorithms
		}),
		new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])  // Inject js code into html
	]
}


## paths.js

// Path module 
// Search according to the current config directory
const path = require('path')

const appDir = process.cwd()

console.log(appDir, '<---')

const resolveApp = (relativePath) => {
    return path.resolve(appDir, relativePath)
}

module.exports = resolveApp



## babel.config.js

// bable's configuration is used to convert js code
// module.exports = {
//     presets: [
//         '@babel/preset-env',
//         {/ / polyfill fills in plug-ins with insufficient babel functions
//             //false: the current js processing will not be filled with polyfill
//             //usage: fill in according to the new syntax used in the user's source code
//             //entry: decide what to fill based on the currently filtered browser
//             useBuiltIns: 'entry',
//             Corejs: 3 / / corejs version is 3
//         }
//     ]
// }

const presets = [
    [
        '@babel/preset-env',
        {  // polyfill fills in plug-ins with insufficient babel functionality
            // false: the current js processing will not be filled with polyfill
            // usage: fill in according to the new syntax used in the user's source code
            // entry: decide what to fill based on the currently filtered browser
            useBuiltIns: 'entry',
            corejs: 3  // corejs version 3
        }
    ],
    [ '@babel/preset-react' ]
]

const plugins = []

console.log(process.env.NODE_ENV, '<-----')

// The value of plugins is determined according to the current packaging mode
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
    plugins.push(['react-refresh/babel'])
}

module.exports = {
    presets,
    plugins
}


## postcss.config.js

module.exports = {
    plugins: [
        require('postcss-preset-env')
    ]
}


## Server.js
const express = require('express')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')

const app = express()

// Get profile
const config = require('./webpack.common.js')
const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler))

// Turn on the service on the port
app.listen(3000, () => {
  console.log('The service runs on port 3000')
})

// function?
// node .\Server.js


## .browserslistr

> 1%
last 2 version
not dead


## babel.config.js

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        userBuilIns: 'usage',  // Code plug-in completion
        corejs: 3  // edition
      }
    ],
    ['@vue/cli-plugin-babel/preset']
  ]
}



## package.js

{
  "name": "vue-app-base",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "webpack serve --config ./config/webpack.common.js --env development",
    "build": "webpack --config ./config/webpack.common.js --env production",
    "ck": "tsc --noEmit",
    "lint": "npm run serve"
  },

  "sideEffects": [
    "./src/title.js"
  ],
  "dependencies": {  
    "core-js": "^3.6.5",
    "vue": "^2.6.11"
  },
  "devDependencies": {},
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ],
  "description": "1. This is a use Vue CLI Created Vue Project infrastructure\r 2. The difference is that I removed it here vue-cli-service(contain webpack Black box tools such as tools)\r 3. The requirement here is to use it directly webpack And the surrounding tools you know Loader,Plugin Restore the packaging task for this project\r 4. Use all the features and functions you know as much as possible",
  "main": "babel.config.js",
  "keywords": [],
  "author": "",
  "license": "ISC"
}


## .eslintrc.js

// Eslint loader is configured in the development environment
const  commonConfig =  require('./webpack.common')
const merge = require('webpack-merge')
const path = require('path')


module.exports = merge(commonConfig,{
    mode:'development',
    devtool:'cheap-module-eval-source-map',
    module:{
        rules:[
            {
                test: /\.js$/, 
                exclude: /node_modules/, 
                use: 'eslint-loader',
                enforce:'pre'
              },
        ]
    },
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        port: 9000,
        hot: true
    }
})

Posted by LDM2009 on Fri, 01 Oct 2021 11:19:32 -0700