webpack4.0以上版本的配置

1、webpack的主要功能:

图片

2、安装

1
    npm install webpack -g

此方式不推荐,因为每个人的webpack版本都不一样,在多人维护同一项目时会发生冲突。

推荐:

1
    npm install webpack webpack-cli -D

webpack版本是4.0以上时需要下载webpack-cli。

3、webpack4.0及以上的基本配置:

1
2
3
4
5
6
7
8
9
10
11

//基于node 遵循commonjs语法
    module.exports = {
        entry: ''//入口
        output: {},//出口
        devServer: {},//开发服务器
        module: {},//模块配置
        plugins: [],//插件的配置
        mode: 'development',
        resolve: {},//配置解析
    };

4、一个完整的webpack例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//webpack.config.js

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

module.exports = {
	mode: 'development',
	entry: './src/main.js',//入口是单独的
	output: {
		path: __dirname + '/dist',
		filename: 'bundle-[hash].js'
	},
	module: {
		rules: [
			{
				test: /\.css$/,//要匹配的文件
				use:[//从右往左 先解析成css 在插入到style标签
					{
						loader: 'style-loader'
					},
					{
						loader: 'css-loader',
						options: {//参数
							modules: true,
							localIdentName: '[name]__[hash:7]'//指定css类名
						}
					},
				]
			},
			{
				test: /\.js$/,
				use: {
					loader: "babel-loader",
					options: {
						presets: [
							"env", "react"
						]
					}
				},
				exclude: /node_modules/
			},
		]
	},
	devServer: {
		//内存中找不到才会找真实的目录
		contentBase: "./",//本地服务器所加载的页面所在的目录 以这个目录启动了个服务(可以试试再次目录下增加其他文件并在浏览器中访问)
		historyApiFallback: true,//不跳转
		inline: true,//实时刷新 命令中如果写了 这里可以不配置 如 webpack-dev-server --inline
		port: 3000,//端口
		compress: true,//服务器压缩
		open: true,//自动打开
		hot: true,//与HotModuleReplacementPlugin配套使用  命令中如果写了 这里可以不配置 如 webpack-dev-server --hot
	},
	devtool: 'eval-source-map',
	plugins:[
	    //在编译好的js中添加注释
		new webpack.BannerPlugin('tianyuan webpack 实例'),

		new CleanWebpackPlugin(),

		new HtmlWebpackPlugin({//new 一个这个插件的实例,并传入相关的参数
			filename: 'index.html',
			template: "./index.html",
			title: '测试首页',//页面中如此引用 <%=htmlWebpackPlugin.options.title%>
			hash: true,//引入文件时自动待一段md5 形如nuild.js?32eh384yresih
			// chunks: ['main'],//规定引入哪个js 与第三个entry配合使用
			minify: {
				removeAttributeQuotes: true,//取出页面中属性值的双引号
				// collapseWhitespace: true,//折叠空行 一般发布到线上需要此配置
			}
		}),

		new webpack.HotModuleReplacementPlugin()//热加载插件 用于局部热更新
	]
};

这是一个简单完整的配置,其中用到几个插件:

1)html-webpack-plugin:找到相应的模板,并将打包后的js引入到此模板中。

文档:html-webpack-plugin

也可以利用tmpl这种的模板进行配置:

1
2
3
4
    new HtmlWebpackPlugin({
        template: __dirname + "/app/index.tmpl.html"
        //...
    }),

index.tmpl.html:

1
2
3
4
5
6
7
8
9
10
11
12
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>tmpl test</title>
    </head>
    <body>
    <div id='root'>

    </div>
    </body>
    </html>

其写法与html一样,只是命名时要以tmpl.html结尾。

2)clean-webpack-plugin:清除webpack打包出来的文件。

clean-webpack-plugin

相关配置

这里要注意的是,如果打包后的目录是dist 括号中什么都不用写。

3)banner-plugin:不需要单独下载,用于给编译后的js文件添加注释。

4)HotModuleReplacementPlugin:webpack自带的插件,与webpack-dev-server命令配合使用,用于做局部热更新。

webpack-dev-server 命令启动后,会在本地启动一个服务,端口与webpack配置有关(默认是8080),此时打包后的文件在内存中,并不在我们的项目dist文件里,

任意修改html文件或者js文件并保存,整个页面都会刷新一遍,在html或者js内容很多的情况下,非常不利于我们的开发,因此采用此插件进行局部更新。具体做法是:

首先在配置文件中引入webpack模块,并在plugins中new一个实例:

1
2
3
    const webpack=require('webpack');
    //...
    new webpack.HotModuleReplacementPlugin()

然后再在入口文件的末尾添加一段代码:

1
2
3
    if (module.hot) {
        module.hot.accept();//只要代码有更新就刷新
    }

与js编译有关的插件先说这几个。

5、entry:

entry配置有几种方式,第一种是4中的写法,这种配置代表只有一个入口。

第二种是入口有一个,引入两个JS打包后的js:

1
    entry: ['./src/main.js', './src/ent.js'],

第三种是入口有多个,分别引入打包后的js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    //...
    entry: {
	    main: './src/main.js',
	    ent: './src/ent.js'
    },
    output: {
        path: __dirname + '/dist',
        filename: '[name].bundle-[hash].js'
    },
    //...
    plugins: [
        //...
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: "./index.html",
            chunks: ['main'],//规定引入main.js
        }),
        new HtmlWebpackPlugin({
            filename: 'ent.html',
            template: "./index.html",
            chunks: ['ent'],//规定引入ent.js
        }),
    ]

6、编译css

1)安装loader :

1
    npm install style-loader css-loader less less-loader stylus stylus-loader node-sass sass-loader -D

注:css-loader 具有热更新的功能。

1)编译less:

在module中添加以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    //...
    module: {
        rules: [
        //...
        {
            test: /\.less$/,
            use: [{
         		loader: 'style-loader',
         	},{
         		loader: 'css-loader',
         	},{
         		loader: "less-loader"
         	}]
        }
        ]
    }

loader的顺序是倒序的,上面的配置先将less文件转成css文件,再将css样式插入到html的style标签中。

2)抽离css样式到一个css文件中,通过link引入编译后的css文件:

1
    npm install extract-text-webpack-plugin@next mini-css-extract-plugin -D

注:a.后者有望取代前者,前者比较稳定,后者还存在点问题;

b.extract-text-webpack-plugin是webpack3提出的插件,webpack4要用需加@next。

文档如下:

extract-text-webpack-plugin

mini-css-extract-plugin

配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
    //...
    module.exports = {
        //...
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ExtractTextWebpackPlugin.extract({
                        use: [{
                            loader: 'css-loader',
                        }]
                    })
                },
                {
                    test: /\.less$/,
                    use: ExtractTextWebpackPlugin.extract({
                        use: [{
                            loader: 'css-loader',
                        },{
                            loader: 'less-loader',
                        }]
                    })
                }
            //...
        },
        //...
        plugins:[
            //...
            new ExtractTextWebpackPlugin({
                filename: 'css/index.css',
            }),
        ]
        //...
    };

但是这种配置方式不具备热更新功能,因此插入到页面上的link标签里的内容如果有变化,需要手动刷新,可以改写成以下方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
    const lessExtract = new ExtractTextWebpackPlugin({
        filename: './css/less.css',
        disable: true,//先禁用
    });
    const cssExtract = new ExtractTextWebpackPlugin({
        filename: './css/css.css',
        disable: true,//先禁用
    });
    //...
    module.exports = {
        //...
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: cssExtract.extract({
                     	fallback: 'style-loader',//上面引入是用disabled禁用,这里再利用fallback在编译后插入到style标签中
                     	use: [{
                     		loader: 'css-loader',
                     	}]
                    })
                },
                {
                    test: /\.less$/,
                    use: lessExtract.extract({
                        use: [{
                            loader: 'css-loader',
                        },{
                            loader: 'less-loader',
                        }]
                    })
                }
            //...
        },
        //...
        plugins:[
            //...
            lessExtract,
            cssExtract,
        ]
        //...
    };

3)去除没有用到的css样式:

1
    npm install purifycss-webpack purify-css glob -D

文档:purifycss-webpack

配置:

1
2
3
4
5
6
7
8
9
10
11
12
    //...
    const PurifycssWebpack = require('purifycss-webpack');
    const glob = require('glob');
    module.exports = {
        //...
        plugins:[
            //...
            new PurifycssWebpack({
                paths: glob.sync(path.resolve('src/*.html')),//这里必须是绝对路径
            }),
        ]
    }

注意事项:必须与ExtractTextWebpackPlugin配套使用,且放在其下面。

4)css3样式添加前缀:

1
    npm install postcss-loader autoprefixer -D

文档:postcss-loader

postcss.config.js配置:

1
2
3
4
5
    module.exports = {
    	plugins: [
    		require('autoprefixer')//自动加前缀
    	]
    };

然后可在module配置的rules中添加一个loader:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    use:[
        {
            loader: 'style-loader'
        },
        {
            loader: 'css-loader',
            options: {//参数
                modules: true,
                localIdentName: '[name]__[hash:7]'//指定css类名
            }
        },
        {
            loader: "postcss-loader"
        },
    ]
1
2
3
4
5
6
7
    use: ExtractTextWebpackPlugin.extract({
        use: [{
            loader: 'css-loader',
        },{
            loader: 'postcss-loader',
        }]
    }),

7、其他插件

1)复制文件

1
    npm install copy-webpack-plugin -D

文档:copy-webpack-plugin

配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    //...
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    module.exports = {
        //...
        plugins:[
            //...
            new CopyWebpackPlugin([
                {
                    from: './src/doc',
                    to: './public'
                }
            ]),
        ]
    }

将./src/doc路径下的文件复制到dist目录的public文件夹下。

8、自己写loader

1) 在配置中添加解析自定义loader的配置:

1
2
3
4
5
6
    resolveLoader: {
        modules: [
            path.resolve(__dirname, './build/rules'),
            'node_modules'
        ]
    },

以上配置是用来解析build/rules文件夹下的js文件的。

2)编写自定义loader:

文件目录如图:图片

reverse-loader index.js:

1
2
3
4
5
6
7
8
    module.exports = function(srcObj) {
        if(srcObj) {
            console.log('---reverse loader input---', srcObj);
            srcObj = src.split('').reverse().join('');
            console.log('---reverse loader output---', srcObj);
        }
        return srcObj;
    };

这个是反转字符串的loader。

static-loader index.js:

1
2
3
4
5
6
7
8
9
10
    /**
     * source为原文件的字符串格式
     */
    let loaderUtils = require('loader-utils');
    module.exports = function(source){
        const options = loaderUtils.getOptions(this) || {};
        console.log('---static loader options---', options);
        source = source.replace(/(\/images\/)(.*?\.(png|gif|jpg))/gi, options.replace);
        return source;
    };

这个是替换图片的loader。

3)webpack中的相应配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    module.exports = {
        //...
        module: {
            rules: [
                {
                    test: /\.(js)$/,
                    use: {
                        loader: 'static-loader',
                        options: {
                            include: [path.resolve(__dirname, '../src')],//或正则
                            replace: process.env.BUILD_ENV === 'development' ? '/images/demo.jpg' : 'https://xx.xx.cc/imgs/no_data.png'
                        }
                    },
                    exclude: /node_modules/,
                },
                {
                    test: /\.json$/,
                    use: {
                        loader: 'reverse-loader'
                    },
                    exclude: /node_modules/,
                }
            ]
        }
    }

9、webpack知识补充:

1)可以在不配置webpack.config.js的情况下直接运行webpack

npx webpack (npx命令要求node版本是8.5以上)

这个命令会做两件事:第一会检测webpack是否安装 没有的话会自动安装一个;第二会直接运行node_modules中bin下的webpack.cmd。

但一般情况下不会采用这种方式,需要自己手动配置一些规则。

2)关于babel-loader

a.babel-loader: 主要解析ES6、ES7等浏览器支持不好的JS语言

b.”babel-core”: “^6.26.3”,”babel-loader”: “^7.1.5”,这两个版本配合使用

3)plugin 和loader 的区别:

loader: 一个转换器,将A文件进行编译形成B文件,单纯的文件转换过程

plugin: 一个扩展器,丰富webpack本身,针对loader结束后,webpack打包的整个过程,并不直接操作文件,会基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛任务。