zoukankan      html  css  js  c++  java
  • 实战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' //公共路径
                        }
                    }
                },

    .

  • 相关阅读:
    go多种uuid生成方式
    go访问mysql基本语法
    go实现分布式唯一ID-snowflake(雪花算法)
    指定时间生成cron表达式
    zookeeper注册与发现
    短地址服务(二)
    java-redis
    短地址服务(一)
    cron表达式详解
    以后本blog所有内容全部转移,并在自建blog更新
  • 原文地址:https://www.cnblogs.com/fightjianxian/p/12755604.html
Copyright © 2011-2022 走看看