实战webpack4.0常用配置与优化

 

 

注意:

1、在webpack里,所有文件都是模块
    例如:JS模块--->模块化(AMD、CMD、ES6 Module、Commonjs)
    关于模块化参见https://www.cnblogs.com/jianxian/p/12753375.html. 
  如下所示

  

  接下来便可以导入使用

  

  最后做下验证输出,可以直接打包生成文件

  

  接下来做下测试,引入脚本文件,打开html文件进行测试

  

  但我们想知道这里为什么是main.js,接下来做个配置文件进行修改

  

 

  接下来开始编写代码,但注意webpack是基于node的,所以必须遵循Commonjs规范

  

  依次填充入口与出口文件

  

 

 

  接下来进行打包测试,则如下所示

  

 

 

  至此便可以实现自定义打包并验证,但不可能每次都需要自己新建html引入验证,所以我们可以在webpack引入服务,给其配置一个开发服务器。

  (1)接下来配置开发服务器webpack-dev-server

    1、首先进行安装

    

 

 

    2、启动指令--npx webpack-dev-server,此时便可以在localhost:8000端口查看文件

    

 

 

    3、为了方便使用指令,我们使用scripts字段设置命令简称

      

    此时执行npm run start或者npm start即可,结果如下

    

 

 

    4、打开指定文件,渲染到指定html文件,而不是文件目录界面

    分析如下,此时打开的是项目跟目录

    

 

 

    所以我们需要配置开发服务器

    

    测试如下,此时再次打开localhost:8000时便会直接到该目录

    

 

 

    

 

 

    5、配置开发服务器端口号、压缩文件、自启动

    

    此时再运行便会自动打开浏览器的http:localhost:3000端口

    

 

 

  (2)webpack插件plugins------动态添加html文件

    目前为止都是手动添加html文件,然后手动引入js文件,最后查看效果的... ...过于繁琐。

    因此我们换个思路,先将打包文件放到src的index.html里,然后再将整个打包

    

    

 

 

    1、下载依赖

>npm i html-webpack-plugin -D

    webpack使用插件有个共同点:即在使用前都必须用node语法即CommonJS语法导入.

    

 

 

    2、编写打包指令缩写,进行打包

    

 

 

    接下来执行npm run build开始打包,结果如下

    

    且里面自动引入了脚本文件js

    

 

 

    3、添加其他参数:修改标题等(这里可以参考npm官方文档进行配置

    

 

    

 

 

    接着配置src/index.html文件,如下所示

    

 

    接下来进行打包并启动服务,效果如下

 

    

 

 

    

 

 

    4、压缩html文件

    

    加上hash后src文件会价格hash随机数值,避免缓存

    

    

 

 

    此外,也可以在src前面价格,随机src文件名,避免缓存

    

 

 

    此时前后都有随机数,如下

    

 

 

    此后每次打包都会产生新文件... ....,接下来配置下删除文件操作,此时需要用到另一个插件clean-webpack-plugin

  

 

 

  1、首先安装依赖

    

 

 

  2、引入插件依赖

    

 

 

  3、开始使用

    

 

 

 

(3)多文件打包问题

  此时入口文件为src/index.js,我们打包时会查找与index.js相关联依赖的文件,例如a.js

  

 

 

  

 

 

  但是此时如果将a和index的关联去掉,如下

  

  

 

 

  此时两个文件便没有任何关联了... ...

  但此时我们如果想让两个文件关联打包,则如下

  

 

 

  如下所示

  

 

 

  此时便会将两个文件都打包进去

  

 

 

 

(4)单页与多页html

  a.html引用index.js文件,b.html引用a.js文件

  

  打包测试如下,只打包了a.js文件... ...

  

 

 

  修改如下,多入口对应多出口

  

 

 

  此时再次打包测试如下,此时index.html引入了两个文件

  

 

 

  

 

 

  但是,我们这里的需求是a.html引用index.js文件,b.html引用a.js文件,所以需要打包多个html文件,所以添加HtmlWebpackPlugin即可

  

  

  打包后如下,且a.html引入两个,b.html引入一个

  

  

 

(5)热更新

  还原之前所有配置,如下

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')/**打包Html插件,自动产生html,并引入打包后的文件 */
let { CleanWebpackPlugin } = require('clean-webpack-plugin')/**手动清除某个文件夹内容,清空指定的目录 */
module.exports = {
    /**入口配置 */
    entry:'./src/index.js',
    /**出口配置 */
    output:{
        filename:'[name].[hash:5].js',/**自定义打包文件名 */
        path:path.resolve(__dirname,'dist')/**node里路径操作需要绝对路径 */
    },
    /**开发服务器配置 */
    devServer:{
        contentBase:'./dist',/**启动目录 */
        port:3000,/**端口号 */
        compress:true,/**服务器压缩 */
        open:true,/**自动打开浏览器 */
        hot:true,/**热更新 */
    },
    /**插件 */
    plugins:[
        /**打包Html插件,自动产生html,并引入打包后的文件 */
        new HtmlWebpackPlugin({
            filename:'a.html', /* 打包出来的文件名*/
            template:path.resolve(__dirname,'./src/index.html'),/**打包的html文件 */
            title:'首页',
            minify:{/**压缩 */
                removeAttributeQuotes:true,/**去除双引号 */
                collapseWhitespace:true,/**折叠代码为一行 */
            },
            hash:true,/**清除缓存用的 */
        }),
        /**清空匹配的路径 */
        new CleanWebpackPlugin()
    ],
    /**模块设置 */
    module:{},
    /**模式设置 */
    mode:'development',
    /**配置解析 */
    resolve:{}
}

  

 

 

  当我们在编辑代码保存时,浏览器会自动更新... ...

  但是有时我们并不想页面所有数据更新,例如vuex和redux状态会丢失,所以我们可以使用插件局部更新

  1、开启开发服务配置

  

 

 

  2、引入插件,webpack内置的哦

  

 

 

  

 

 

  3、分析:此时还是会整个页面刷新,因为并不知道修改了哪个模块,所以需要添加判断(热更新应用通知,实现局部刷新,即结合该方法的回调函数实现该模块的更新

  

 

 

  接下来进行优化,直接调用即可

  

 

 

  注意位置:在index.js文件进行配置添加

  

 

 

 

  

(6)样式打包

  1、新建src/index.css文件

    

 

 

  2、分析:如果直接引入样式文件进行打包,则无效... ...因为webpack默认只打包js文件

    

 

 

    所以处理css模块需要利用loader

    

  3、安装相关依赖

①style-loader将样式代码插入style
②css-loader将css作为模块,插入style标签内部
③less、less-loader
④stylus、stylus-loader
⑤node-sass、sass-loader
...

    这里我们演示下css-loader、style-loader、less、less-loader

    

 

 

    接下来开始配置

  4、配置module模块处理规则,写成对象形式方便传参option(注意解析顺序:自下而上,因为先解析成css模块,再将其放到style内

    

    接下来新建一个less文件

    

 

 

    

 

 

    然后引入less  

    

 

 

    结果如下

    

 

 

    

 

 

 

(7)样式抽离---css 和 less 抽离到同一个 css 文件 common.css 里

  此时存在问题,style标签太多,我们利用link引入更加优雅一些...

  测试可以得知改变less文件,也可以触发热更新

  

 

  原理如下:CSS-loader具有热更新功能

 

  

 

 

  如果想实现样式抽离,需要安装下面两个plugin插件

  

 extract-text-webpack-plugin在webpack3里就存在,在新版本后面加@next后缀
 mini-css-extract-plugin将来可能替代上述插件的插件,目前不太稳定

  1、引入

  

 

 

  2、使用:注意这里我们要将其改为link形式,所以不再需要style-loader

  

  3、实例化调用插件方法

  

  4、抽离文件名

  

  5、打包测试如下

  

 

(8)样式抽离---分开抽离,分别把 css 和 less 放在两个 css 文件中 link 到页面

 

 

 

  

 

 

  

 

 

  

 

 

  打包测试结果

  

 

 

 

  

(9)样式抽离--最新方案

  弱点:只能合成一个css文件,不能分开抽离

从上图我们可以看到,我们所写的css、less样式都会放到head标签中,那么我们如何单独把css的内容抽离出来用link标签的形式引入呢:

  • 首先,先安装抽离 css 的插件 : yarn add mini-css-extract-plugin -D
  • 安装好之后,在 配置文件中 引入:let MiniCssExtractPlugin = require('mini-css-extract-plugin')
  • 然后在配置文件中的插件配置中进行配置:
plugins: [ //数组, 放着所有的 webpack插件
        new MiniCssExtractPlugin({
            filename:'main.css', //抽离出来的css的文件的名字
        })
    ],
  • 然后选择,到底是 css 文件要抽离,还是 less 文件要抽离,那个要抽离就给那个 加上抽离插件的内置loader。(在模块中的 css 、less 规则中加 ):如下:
module: { //模块
        rules: [ //规则
            {
                test: /\.css$/, //用正则来匹配以 css 结尾的文件
                use: [
                    MiniCssExtractPlugin.loader,//这个loader的作用是:抽离出来 css然后用 link 标签引入到 模板文件中
                    'css-loader'
                ]

![](https://user-gold-cdn.xitu.io/2019/11/14/16e68118b17b28e6?w=1477&h=705&f=jpeg&s=127105)            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,//这个loader的作用是:抽离出来 css然后用 link 标签引入到 模板文件中
                    'css-loader',
                    'less-loader' //把 less --->转换为 css
                ]
            }
        ]
    }
  • 运行npm run build命令,看一下是否单独抽离出来css文件:

可以看到,我们的css文件已经被单独抽离出来了,启动一下服务看一下页面效果:

   

   

现在已经变成抽离出来的css文件是用link标签来引入的。



 (10)样式抽离后的注意事项

  样式抽离后因为放到link标签,所以更改样式时,服务器无法热更新哦。设置如下

  

 

  将disable属性改为true后便无法将其改为link引入,即该设置无效,便可以在开发时候热更新,上线前记得改为false。

  注意2:fallback改为style-loader,即当无法改为link引入时,使用style内敛,以此实现热更新目的

  

 

(11)多余样式代码的删除

  场景:项目引入bootstrap,但有很多多余没用的而样式,我们可能只用到一两种... ....

  如下所示,这里我们手动添加一些无用的多余样式

  

 

  我们希望打包时,如果用不到,则不打包这些样式代码,此时需要用到插件purifycss-webpack,它会在打包时调用purify-css插件,且搜索时需要glob插件

  1、安装依赖

  

 

  2、引入使用(使用注意事项,必须在css-plugin的下面,因为需要先去除,再打包)

  

  结合文档看先使用规范

  

  

  结果如下

  

 

  

(12)css代码自动添加前缀

  如下所示,希望在添加时自动加上前缀

  

  1、安装依赖

npm install postcss-loader autoprefixer -D

  2、添加配置文件src/postcss.config.js

  

  3、使用

  

 

  4、打包测试

  

 

 

  

 

 

(13)解析ES6

参考文章:https://juejin.im/post/5e195c6b6fb9a02fcd130b69

1.ES6 或者 更高级的语法 转化为 ES5  (babel)

1.安装 babel-loader:转换加载器,和 babel/core(babel 的核心),和babel/preset-env (转化模块)

yarn add babel-loader @babel/core @babel/preset-env
复制代码

2.安装完成之后,在配置文件中配置 js规则:

 {
                test: /\.js$/,
                use:{
                    loader: 'babel-loader',
                    options: { // 用 babel-loader,需要把 es6 转换为 es5
                        presets: [  //预设库
                            '@babel/preset-env'  //包含把es6转换为es5的模块
                            '@babel/preset-react' //解析 react语法
                        ]
                    }
                }
            },
复制代码
//配置完成后就可以解析 `es6` 语法。 
   
//更高一级的语法的配置:(注意:先安装完在配置)
   
   {
                   test: /\.js$/,
                   use:{
                       loader: 'babel-loader',
                       options: { // 用 babel-loader,需要把 es6 转换为 es5
                           presets: [  //预设库
                               '@babel/preset-env'  //包含把es6转换为es5的模块
                           ],
                           plugins: [
                               //更高级的语法解析(如装饰器写法)
                          ["@babel/plugin-proposal-decorators", { "legacy": true }],
                          ["@babel/plugin-proposal-class-properties", { "loose" : true }]
                           ]
                       }
                   }
               },
复制代码

2.ES6 或者 更高级的语法 转化为 ES5 常用插件:

  1. @babel / plugin-transform-runtime (可以处理异步,如 Promise等)代码运行时的包 开发依赖:

    yarn add @babel / plugin-transform-runtime -D 先进行插件的安装

  2. @babel/runtime : 这个包上线时需要,所以安装时不要加 -D

    yarn add @babel/runtime

  3. 安装好之后,进入到配置文件中配置安装好的插件:

		{
                test: /\.js$/,
                use:{
                    loader: 'babel-loader',
                    options: { // 用 babel-loader,需要把 es6 转换为 es5
                        presets: [  //预设库
                            '@babel/preset-env'  //包含把es6转换为es5的模块
                        ],
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ["@babel/plugin-proposal-class-properties", { "loose" : true }],
                            "@babel/plugin-transform-runtime"  //加入到这个位置
                        ]
                    }
                },
                include:path.resolve(__dirname,'src'), //找 src下面的 js
                exclude:/node_modules/  //不包含 node_modules 下面的 js
            },
复制代码

默认找到的是全部的 js, 我们还得写一些规则来让它只找 src 下面的 js文件。

4.还有一些更高级的语法不支持转换,安装一个补丁模块:

yarn add @babel/polyfill 这个模块在代码运行时需要,所以安装时不要加 -D。

用的时候需要在上面引入这个模块: require('@babel/polyfill')

3.JS校验:(校验器:eslint)

  1. 需要先安装 eslinteslint-loader

    yarn add eslint eslint-loader -D

  2. 然后在配置文件中的模块配置中去配置 js 规则:

	{
            	//在配置一个 js 规则,用来校验 js
                test: /\.js$/,
                use: {
                    loader: 'eslint-loader',
                    options: {
                        enforce: 'pre' // 强制  强制在下一个 loader 之前执行  post 是后面
                    }
                }
            },
            {
                test: /\.js$/,
                use:{
                    loader: 'babel-loader',
                    options: { // 用 babel-loader,需要把 es6 转换为 es5
                        presets: [  //预设库
                            '@babel/preset-env'  //包含把es6转换为es5的模块
                        ],
                        plugins: [
                            ["@babel/plugin-proposal-decorators", { "legacy": true }],
                            ["@babel/plugin-proposal-class-properties", { "loose" : true }],
                            "@babel/plugin-transform-runtime"
                        ]
                    }
                },
                include: path.resolve(__dirname, 'src'), // 包含 src 下面的 js 文件
                exclude: /node_modules/  // 去除掉 node_modules
            },
复制代码

4.全局变量引入问题(第三方模块的使用):

loader 的类型:pre 前面执行的 loader, normal 普通 loader,内联 loader,post 后置 loader。

jquery 举例说明:

​ >>>>> 内联 loader,就是在 代码中就可以直接使用的 loader。

​ 1. 先安装 jqueryyarn add jquery

​ 2. 在代码中引入:import $ from 'jquery'

​ 3. 将 $ 符 暴露到全局去:那么这就需要一个暴露 全局的 loader:expose-loader ,这个loader是内联的。

import $ from 'expose-loader?$!jquery'
复制代码

​ 这是内联 loader 在代码中的直接用法。 jquery 暴露 出 一个 $ 符 到全局。

  1. 也可以在 配置文件中去配置 内联 loader:

    module: { //模块
            rules: [ //规则   
                {
                    test: require.resolve('jquery'), //只要引用了 jquery 就去匹配
                    use: 'expose-loader?$'
                },
            ]
    }
    复制代码
  2. 注解的方式: 在每个模块中注入 $ 对象:

    • 这个时候需要 webpack 的插件: 先要引入 webpack

    • let webpack = require('webpack')
      复制代码
    • 然后在配置文件的 插件配置中 去配置:

    • new webpack.ProvidePlugin({  // 在每个模块中都注入 $ (提供插件)
                 $:'jquery'
             })
      复制代码
  3. 在模板中直接引入 jquerycdn ,但是这样在打包的时候会将 jquery 一起打包,这个时候 需要在 配置文件中添加一个属性来不打包 jquery

    // 表明这是外部引入的,并不需要打包。
    externals: {
    jquery: '$' 
    }
    复制代码

5.webpack 打包图片:

js 中创建图片来引入:

// 1)在 js 中创建图片来引入
let image = new Image()
image.src = './logo.png' //就是一个普通的字符串
document.body.appendChild(image)
复制代码

这样来引入的话,找不到这张图片,因为这样写的话图片只是一个普通的字符串。要用es6的语法来导入图片.

import logo from './logo.png' //把图片引入,返回的结果是一个新的图片地址
let image = new Image() 
console.log(logo)
image.src = logo
document.body.appendChild(image)
复制代码

这样写的话是不支持的,需要引入一个 loader 来实现这种写法:file-loader

安装完成 loader 之后,我们需要到配置文件中去配置 加载图片的规则:

module: { //模块
        rules: [ //规则   
            {
                test: /\.(png|jpg|gif)$/,
                use: "file-loader"
            },
        ]
}
复制代码

css 中引入图片:

background: url('图片地址') /* 可以直接这样来写,这是默认支持的,因为我们用了 css-loader css-loader会吧这个转化为 require()这种写法*/
复制代码

html 中直接引入

<img src="./logo.png" alt="">
复制代码

这样写会报错,因为在我们打包的文件中根本找不到这张图片。这个时候我们需要一个 loader 来支持这种写法。

yarn add html-withimg-loader -D 这个 loader 会帮我们解析 html 编译图片.

安装完成之后到配置文件中配置我们的 loader:

module: { //模块
        rules: [ //规则   
            {
                test: /\.html$/,
                use: 'html-withimg-loader'
            },
        ]
}
复制代码

一般我们用于图片的loader 不是用 file-loader, 而是用 url-loader

			{
                test: /\.(png|jpg|gif)$/,
                use: {
                    // 做一个限制,当我们的图片 小于多少k的时候 用base64 来转换
                    // 否则用 file-loader 来产生真实的图片
                    loader: "url-loader",
                    options: {
                        limit: 1
                    }
                }
            },
复制代码

6.打包文件分类

图片放到 img 文件夹下面:

在配置文件中的 图片 规则中加上一个输出的路劲:

 		{
                test: /\.(png|jpg|gif)$/,
                use: {
                    // 做一个限制,当我们的图片 小于多少k的时候 用base64 来转换
                    // 否则用 file-loader 来产生真实的图片
                    loader: "url-loader",
                    options: {
                        limit: 1,
                        outputPath: 'img/' //这样打包的图片就会放到 img 文件夹下面
                    }
                }
            },
复制代码

这样就会把图片生成到 img 文件夹下面。

css 文件生成到 css 文件夹下面:

在配置文件中,压缩 css 的插件中加入路径:

new MiniCssExtractPlugin({
            filename:'css/main.css', //抽离出来的css的文件的名字
        }),
复制代码

如何在 引用 资源的时候加上一个域名,在输出的时候加上一个公共的路径:

 output: {  //出口
        filename: 'bundle.js', //打包后的的文件名
        path: path.resolve(__dirname, 'build'),  
        publicPath: 'http://www.fanqiang.com' //加上一个公共的路径
    },
复制代码

这样的话引用的资源(cssjsimg等)都会加上公共的路径。

​ 如果你只想要给某一个资源前面加上公共的路径,比如 图片上面加上公共路径,那么就不要在出口中写,只需要在 图片规则中定义即可

{
                test: /\.(png|jpg|gif)$/,
                use: {
                    // 做一个限制,当我们的图片 小于多少k的时候 用base64 来转换
                    // 否则用 file-loader 来产生真实的图片
                    loader: "url-loader",
                    options: {
                        limit: 1,
                        outputPath: '/img/',
                        publicPath: 'http://www.fanqiang.com' //公共路径
                    }
                }
            },

 

 

 

 

 

 

 

.

posted @ 2020-04-22 20:16  剑仙6  阅读(344)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线