webpack工具学习loader的后续和插件(二)

timg.jpeg
前面我们知道webpack中loader是转化js之外的文件工具,那我们就来认知一下常用的loader

1. less-loader工具处理less文件

less文件

image.png

js文件

image.png

1.配置项目文件 npm init -y

  1. 安装webpack
    sudo npm install --save-dev webpack
    npm install --save-dev webpack-cli

3.安装less-loader
sudo npm install --save-dev less 安装less
npm install --save-dev less-loader 安装less转化工具
sudo npm install --save-dev css-loader 安装css转化工具
npm install style-loader --save-dev 安装style-loader

4.配置 webpack.config.js 文件


const  path = require("path");

module.exports = {

    devtool: "cheap-module-eval-source-map",
    mode: "development",
    entry: "./index.js",
    output: {
        /*
        filename: 指定打包之后的JS文件的名称
        * */
        filename: "bundle.js",
        /*
        path: 指定打包之后的文件存储到什么地方
        * */
        path: path.resolve(__dirname, "bundle")
    },
    module: {
        rules:[
            {
                test:/\.less$/,
                use: [{
                    //将css代码放到 head中
                    loader: "style-loader" // creates style nodes from JS strings
                }, {
                    //将css转化模块代码
                    loader: "css-loader" // translates CSS into CommonJS
                }, {
                    //将less转为css代码
                    loader: "less-loader" // compiles Less to CSS
                }]
            }
        ]
    }

};

5.打包 npx webpack

后续的 打包scss文件 和这个流程一样

安装scss sudo npm install sass-loader node-sass webpack --save-dev 这个命令行其实 安装2个 一个是sass,sass-loader

postcss-loader 转化工具

首先说明一下PostCSS是什么?

PostCSS是一款使用插件去转换CSS的工具,比如:autoprefixer(自动补全浏览器前缀),postcss-pxtorem(自动把px代为转换成rem)

安装postcss-loader加载器

  1. npm i -D postcss-loader 安装postcss-loader
  1. npm i -D autoprefixer 安装插件

3.在webpack.config中配置 postcss-loader,在css-loader or less-loader or sass-loader之前添加postcss-loader
用到那个 css的loader就在其后面加载

image.png

4.创建 postcss.config.js配置文件

module.exports = {
    plugins: {
        "autoprefixer": {
            "overrideBrowserslist": [
                "ie >= 8", // 兼容IE7以上浏览器
                "Firefox >= 3.5", // 兼容火狐版本号大于3.5浏览器
                "chrome  >= 35", // 兼容谷歌版本号大于35浏览器,
                "opera >= 11.5" // 兼容欧朋版本号大于11.5浏览器,
           
            ]
        }
    }
};
image.png

2. Plugin 插件

  • plugin插件就是用来扩展webpack的功能,当然loader也是扩展了webpack的功能 ,但是它只专注于转化文件这一个领域。

我们之前在说loader的时候,每次打包转化后的文件,必须将index.html复制一份到bundle目录下才可以运行,Plugin中的插件就可以解决上述的一个问题

2.1 HtmlWebpackPlugin插件

  • HtmlWebpackPlugin会在打包结束之后自动创建一个index.html, 并将打包好的JS自动引入到这个文件中
  • 默认情况下 HtmlWebpackPlugin生成的index.html文件是一个空的文件
  • 如果想指定原来的index.html,在创建HtmlWebpackPlugin对象的时候,需要做如下配置
new HtmlWebpackPlugin({
    //指定原来的模板对象
    template: "index.html",
    minify: {
      //生成的html的压缩文件
        collapseWhitespace: true
    }
})
  1. npm install --save-dev html-webpack-plugin 安装 HtmlWebpackPlugin

2.在webpack.config.js中配置

//导入path模块
const path = require("path");
//导入 插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    /*
    配置sourcemap
    development: cheap-module-eval-source-map
    production: cheap-module-source-map
    * */
    devtool: "cheap-module-eval-source-map",
    /*
    mode: 指定打包的模式, 模式有两种
    一种是开发模式(development): 不会对打包的JS代码进行压缩
    还有一种就是上线(生产)模式(production): 会对打包的JS代码进行压缩
    * */
    mode: "development", // "production" | "development"
    /*
    entry: 指定需要打包的文件
    * */
    entry: "./index.js",
    /*
    output: 指定打包之后的文件输出的路径和输出的文件名称
    * */
    output: {
        /*
        filename: 指定打包之后的JS文件的名称
        * */
        filename: "bundle.js",
        /*
        path: 指定打包之后的文件存储到什么地方
        * */
        path: path.resolve(__dirname, "bundle")
    },
    /*
    module: 告诉webpack如何处理webpack不能够识别的文件
    * */
    module: {
        rules: [
            // 打包字体图标规则
            {
                test: /\.(eot|json|svg|ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            // 指定打包后文件名称
                            name: '[name].[ext]',
                            // 指定打包后文件存放目录
                            outputPath: 'font/',
                        }
                    }
                ]
            },
            // 打包图片规则
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // 指定图片限制的大小
                            limit: 1024 * 100,
                            // 指定打包后文件名称
                            name: '[name].[ext]',
                            // 指定打包后文件存放目录
                            outputPath: 'images/',
                        }
                    }
                ]
            },
            // 打包CSS规则
            {
                test: /\.css$/,
                // use: [ 'style-loader', 'css-loader' ]
                use:[
                    {
                        loader: "style-loader"
                    },
                    {
                        loader: "css-loader",
                        options: {
                            // modules: true // 开启CSS模块化
                        }
                    },
                    {
                        loader: "postcss-loader"
                    }
                ]
            },
            // 打包LESS规则
            {
                test: /\.less$/,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader"
                }, {
                    loader: "less-loader"
                },{
                    loader: "postcss-loader"
                }]
            },
            // 打包SCSS规则
            {
                test: /\.scss$/,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader"
                }, {
                    loader: "sass-loader"
                },{
                    loader: "postcss-loader"
                }]
            },
        ]
    },
    /*
    plugins: 告诉webpack需要新增一些什么样的功能
    * */
    plugins: [new HtmlWebpackPlugin({
        // 指定打包的模板, 如果不指定会自动生成一个空的
        template: "./index.html",
        minify: {
            // 告诉htmlplugin打包之后的html文件需要压缩
            collapseWhitespace: true,
        }
    })]
};
  1. npx webpack 打包 项目文件

2.2 css-plugin插件

  • 就是把css代码单独打包一个.css文件中
  • mini-css-extract-plugin是一个专门用于将打包的CSS内容提取到单独文件的插件
  1. npm install --save-dev mini-css-extract-plugin 安装

2.在webpack.config中配置mini-css-extract-plugin
2.1导入

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

//在 plugin中添加插件
new MiniCssExtractPlugin({
    filename: './css/[name].css',
})

2.2 替换style-loader loader: MiniCssExtractPlugin.loader,

image.png

通过 mini-css-extract-plugin打包出来的css代码是没有压缩的,如果想要压缩,需要另外一个插件 optimize-css-assets-webpack-plugin 压缩css, terser-webpack-plugin压缩js

npm install --save-dev optimize-css-assets-webpack-plugin 安装插件
npm install --save-dev terser-webpack-plugin 安装压缩js插件

2,引入和配置插件

//导入插件
const TerserJSPlugin = require('terser-webpack-plugin');

 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

// 配置webpack优化项 module.exports
optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
}

image.png

2.3 webpack.config中的 watch和devServer配置

我们在开发阶段,需要不断的编写代码和编译,不能编写一次代码就打包一次 运行看结果,这样很是浪费,所以就需要webpack.config中添加一些配置,watchdevServer

他们的作用都是监听打包文件变化,当它们修改后会重新编译打包

module.exports = {
//告诉webpack重新编译
    watch: true,
    watchOptions: {
        aggregateTimeout: 300, // 防抖, 和函数防抖一样, 改变过程中不重新打包, 只有改变完成指定时间后才打包
        poll: 1000, // 每隔多少时间检查一次变动
        ignored: /node_modules/ // 排除一些巨大的文件夹, 不需要监控的文件夹
    },
}
  • devServer的配置 和watch 有所不同

webpack-dev-server可以将我们打包好的程序运行在一个服务器环境下,还可以解决企业开发中"开发阶段"的跨域问题

1、npm install webpack-dev-server --save-dev 安装

2.在webpack.config配置

module.exports = {
    devServer: {
        contentBase: "./bundle", // 打包后的目录
        open: true, // 是否自动在浏览器中打开
        port: 3030 // 服务器端口号
    },
 proxy: [{
            context: ["/user", "/login"],
            target: "http://127.0.0.1:3000",
            changeOrigin: true,     // 域名跨域
            secure: false,          // https跨域
            // pathRewrite:{"": "/xxx"} // 路径重写, 将路径中的xxx替换为空
        }],
}

注意: 通过webpack-dev-server自动打包生成的bundle.js文件并没有真正的放到物理磁盘中,而是放在内存中,这样不会影响网页的性能

缺点:通过webpack-dev-server可以实现实时监听打包内容的变化,每次打包之后都会自动刷新网页,那么通过JS动态添加的元素,在网页刷新的时候就会消失,为了解决这个问题,需要在devServer中开启 热更新热更新插件, 会在内容发生改变的时候时时的更新修改的内容但是不会重新刷新网站

2.4 HMR(HotModuleReplacementPlugin) 热更新插件的使用
  1. HotModuleReplacementPlugin是一个内置插件, 所以不需要任何安装直接引入webpack模块即可使用
  1. devServer中开启热更新
    hot: true, 开启热更新
    hotOnly: true 即使热更新不生效,浏览器也不自动刷新

3.在 webpack.config.js中创建热更新插件 new Webpack.HotModuleReplacementPlugin()

需要注意的是:

  • 如果是通过style-loader来处理CSS, 那么经过前面两步就已经实现了热更新
  • 如果是通过MiniCssExtractPlugin.loader来处理CSS, 那么还需要额外配置MiniCssExtractPlugin.loader
    options:{ hmr: true }
const path = require("path");

//引入webpcak 创建热更新插件
const Webpack = require("webpack");

module.exports = {
    /*
    devServer: 自动检测文件变化配置
    * */
    devServer: {
        contentBase: "./bundle",
        open: true,
        port: 9090,
        proxy: [{
            context: ["/user", "/login"],
            target: "http://127.0.0.1:3000",
            changeOrigin: true,     // 域名跨域
            secure: false,          // https跨域
    
        }],
        hot: true, // 开启热更新, 只要开启了热更新就不会自动刷新网页了
        hotOnly: true // 哪怕不支持热更新也不要刷新网页
    },

    
    devtool: "cheap-module-eval-source-map",
    mode: "development", // "production" | "development"
    entry: "./src/js/index.js",
    output: {
        filename: "js/bundle.js",
        path: path.resolve(__dirname, "bundle")
    },
    /*
    module: 告诉webpack如何处理webpack不能够识别的文件
    * */
    module: {
        rules: [
            // 打包CSS规则
            {
                test: /\.css$/,
                use:[
                    {
                        // loader: "style-loader"
                      //如果使用MiniCssExtractPlugin.loader,在使用热更新的时候,就需要 配置 options
                        loader: MiniCssExtractPlugin.loader,
                        options:{
                            hmr: true
                        }
                    },
      // 如果是 css-loade,系统会自动处理热更新
                    {
                        loader: "css-loader",
                        options: {
                            // modules: true // 开启CSS模块化
                        }
                    },
                
                ]
            },
            ]
       
    },
    /*
    plugins: 告诉webpack需要新增一些什么样的功能
    * */
    plugins: [
  
        //创建热更新插件
        new Webpack.HotModuleReplacementPlugin()
    ]
};

需要注意第二点是: 对于css模块而言, 在css-loader中已经帮我们实现了热更新, 只要css代码被修改就会立即更新,但是对于JS模块,系统默认并没有实现热更新,需要开发人员手动实现

 // 判断是否开启热更新
if(module.hot){
// 监听指定那个JS模块变化
// 比如:xxxx.js
    module.hot.accept("./xxxx.js", function () { 
    // 这里实现 要热更新的代码
    });
}

3.Babel官网

作用: 我们在开发过程中,可能使用ES6/7/8语言,但是在低级版本浏览器中,可能 不识别ES6/7/8,所以Babel插件,就是可以帮助我们把ES678高级语法转换为ES5低级语法

  1. npm install --save-dev babel-loader @babel/core 安装babel-loader@babel/core的核心库

2.npm install @babel/preset-env --save-dev 安装 preset-env插件,把高级JS语法转化了 ES2015+

注意:es678中的语法中,有的可能是在ES5中没有对应关系,也就是es678新增的一些语法,那么在转化的时候就需要 安装 polyfill

3.npm install --save @babel/polyfill 安装polyfill
npm install --save-dev @babel/plugin-transform-runtime 安装plugin-transform-runtime
npm install --save @babel/runtime 安装@babel/runtime

4.配置文件 在module节点下的rules数组中,添加一个新的匹配规则``
exclude是排除node_modules文件目录

{ 
 text:/\.js/, 
loader:"babel-loader",
exclude:/node_modules/,
options:{
 "presets": ["@babel/preset-env",{
        targets: {
              //告诉babel 需要兼容哪些浏览器
                "chrome": "58",
                "ie": "10"
        },
      //只打包我用的 js语法 没有用到的 不打包
         useBuiltIns: "usage",
         "plugins": [
                        [
                            "@babel/plugin-transform-runtime",
                            {
                                "absoluteRuntime": false,
                                "corejs": 2,
                                "helpers": true,
                                "regenerator": true,
                                "useESModules": false
                            }
                        ]
                    ]
    }]
 }

}

注意点:
"corejs": false, 还是全局注入,还是会污染全局环境
"corejs": 2, 则不会污染全局环境需要安装@babel/runtime-corejs2
npm install --save @babel/runtime-corejs2

3.图片的处理

我们知道file-loaderurl-loader可以将HS或者css中用到的图片打包到指定的目录,但是他们2个不可以打包html代码中的用到的图片,还有一般图片可能可有几kb/100多kb,有时还需要压缩,甚至也需要自己合并图片,比如自己合并精灵图所以就需要下面一些 loader工具

1.打包html代码 html-withimg-loader github官网地址
npm install html-withimg-loader --save

需要如下规则

{
    test: /\.(htm|html)$/i,
    loader: 'html-withimg-loader'
}

2.图片压缩loader,可以处理png/jpg/jpeg/gif/svg/werp
npm install image-webpack-loader --save-dev 安装image-webpack-loader

配置

rules: [{
  test: /\.(gif|png|jpe?g|svg)$/I,
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: {
        mozjpeg: {
          progressive: true,
          quality: 65
        },
        // optipng.enabled: false will disable optipng
        optipng: {
          enabled: false,
        },
        pngquant: {
          quality: [0.65, 0.90],
          speed: 4
        },
        gifsicle: {
          interlaced: false,
        },
        // the webp option will enable WEBP
        webp: {
          quality: 75
        }
      }
    },
  ],
}]
  1. 图片的合并,postcss这个工具里面有一个插件 postcss-sprites 用来合并图片成精灵图
    npm install --save -d postcss-sprites postcss 安装postcss-sprites 和postcss

配置 新建postcss.congif.js文件

module.exports = {
    plugins: {
      //自动补全前缀插件
        "autoprefixer": {
            "overrideBrowserslist": [
                "ie >= 8", // 兼容IE7以上浏览器
                "Firefox >= 3.5", // 兼容火狐版本号大于3.5浏览器
                "chrome  >= 35", // 兼容谷歌版本号大于35浏览器,
                "opera >= 11.5" // 兼容欧朋版本号大于11.5浏览器,
            ]
        },
        // "postcss-pxtorem": {
        //     rootValue: 100, // 根元素字体大小
        //     // propList: ['*'] // 可以从px更改到rem的属性
        //     propList: ["height"]
        // }
    //图片合并插件
        "postcss-sprites": {
            // 告诉webpack合并之后的图片保存到什么地方
            spritePath: "./bundle/images",
            // 告诉webpack合并图片的时候如何分组
            groupBy: function (image) {
                // url: '../images/animal/animal1.png',
                let path = image.url.substr(0, image.url.lastIndexOf("/"));
                // console.log(path, "!!!!!!");
                let name = path.substr(path.lastIndexOf("/") + 1);
                // console.log(name, "!!!!!!!!");
                return Promise.resolve(name);
            },
            //告诉插件 哪些图片不需要合并
            filterBy: function (image) {
                let path = image.url;
                if(!/\.png$/.test(path)){
                   return Promise.reject();
                }
                return Promise.resolve();
            }
        }
    }
};

注意:在使用loader处理图片时,有可能会打包完整之后,图片并没有完整的显示,原因是路径可能是错误的, 需要在url-loader图片处理规则中,配置optionspublicPath属性,指定服务图片的地址

4. ESlint

-ESLint 是一个插件化的javascript 代码检测工具,可以检查常见的JS错误,也可以惊醒代码规范

  1. 安装 pm install eslint-loader --save-dev loader工具

npm install eslint --save-dev 安装ESLint

2.在webpack.config.js中配置 module中的rules规则

  module: {
         rules: [
              // 检查编码规范的规则
            {
                // enforce: "pre"作用: 让当前的loader再其它loader之前执行
                enforce: "pre",
                test: /\.js$/,
                //过滤掉那个目录
                exclude: /node_modules/,
                //包含那个目录
                include: path.resolve(__dirname, "index.js"),
                loader: 'eslint-loader',
                options: {
                    // eslint options (if necessary)
                    //自动修复错误
                    fix: true
                },
            }

      ]
 }

3.配置.eslintrc.js文件

module.exports = {
  /*
  不重要,永远写true
  * */
  root: true,
  parserOptions: {
    // parser: 'babel-eslint',
    /*
    默认设置为 3,5(默认), 你可以使用 6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本
    * */
    "ecmaVersion": 10,
    /*
    设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)。
    * */
    "sourceType": "module",
    /*
    ecmaFeatures - 这是个对象,表示你想使用的额外的语言特性:
    globalReturn - 允许在全局作用域下使用 return 语句
    impliedStrict - 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
    jsx - 启用 JSX
    * */
    "ecmaFeatures": {}
  },
  // 指定代码运行的宿主环境
  env: {
    browser: true, // 浏览器
    node: true, // node
    /*
    支持 ES6 语法并不意味着同时支持新的 ES6 全局变量或类型(比如 Set 等新类型)。
    对于 ES6 语法,使用 { "parserOptions": { "ecmaVersion": 6 } }
    * */
    es6: true,
  },
  extends: [
      /*
      引入standard代码规范
      * */
    // https://github.com/standard/standard/blob/master/docs/RULES-en.md
    'standard'
  ],
  /*
  扩展或覆盖规则
  * */
  rules: {
    // 强制语句结束添加,分号
    semi: ["error", "always"],
    // 强制缩进2个空格
    indent: ["error", 4],
    // 方法名和刮号之间不加空格
    'space-before-function-paren': ['error', 'never'],
    "no-unexpected-multiline": "off"
  }
};

5.配置webpack.config.js文件的优化

5.1提取webpack.config.js公用部分

我们知道不同的环境配置文件不太一样,比如开发环境和上线环境 就是要区别开的,所以就需要我们,提取出共通的配置文件,比如: 文件入口entry,打包输入的路径配置output,CSS的处理等。 这么久需要用到webpack-merge插件配置
npm install --save-d webpack-merge 安装

比如提取的公用配置文件webpack.config.common.js,开发环境的为webpack.config.dev.js,生产环境的是webpack.config.pro.js,那么假设在开发环境中使用时,就需要在webpack.config.dev.js做如下配置

//打包的时候生成一个index.ml文件
const Webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//引入公用的配置文件
const CommonConfig = require("./webpack.config.common.js");
//引入webpack-merge配置插件
const Merge = require("webpack-merge");

//配置文件
const DevConfig = {
    /*
    devServer: 自动检测文件变化配置
    * */
    devServer: {
        contentBase: './bundle',
        open: true,
        port: 9090,
        proxy: [{
            context: ['/user', '/login'],
            target: 'http://127.0.0.1:3000',
            changeOrigin: true, // 域名跨域
            secure: false, // https跨域
            pathRewrite: { '': '/api' } // 路径重写, 将路径中的api替换为空
        }],
        hot: true, // 开启热更新, 只要开启了热更新就不会自动刷新网页了
        hotOnly: true // 哪怕不支持热更新也不要刷新网页
    },
    /*
    配置sourcemap
    development: cheap-module-eval-source-map
    production: cheap-module-source-map
    * */
    devtool: 'cheap-module-eval-source-map',
    /*
    mode: 指定打包的模式, 模式有两种
    一种是开发模式(development): 不会对打包的JS代码进行压缩
    还有一种就是上线(生产)模式(production): 会对打包的JS代码进行压缩
    * */
    mode: 'development', // "production" | "development"
    /*
    plugins: 告诉webpack需要新增一些什么样的功能
    * */
    plugins: [
        new HtmlWebpackPlugin({
            // 指定打包的模板, 如果不指定会自动生成一个空的
            template: './src/index.html',
        }),
        new Webpack.HotModuleReplacementPlugin()
    ]
};


//Merge 配置
module.exports = Merge(CommonConfig, DevConfig);


更改package.json里面的脚本命令

"scripts": {
    "start": "npx webpack-dev-server --config webpack.config.dev.js",
    "dev": "npx webpack --config webpack.config.dev.js",
    "prod": "npx webpack --config webpack.config.prod.js"
  },
5.2代码优化分割

所谓的代码分割就是: 打包在多次打包的时候,打开网页需要都需要下载新的打包文件,这样会消耗性能,就需要把一些没有更改的文件在第一次打开网页的时候,缓存下来,那么在修改其他文件之后,在打包的时候,只需要下载新修改的文件即可。需要在webpack.config.js文件中添加一下配置

optimization: {
    splitChunks: {
        chunks: "all"
    }
},

5.3 异步加载代码 和 Prefetching

有些模块需要用到的时候再去加载,懒加载
Prefetching:空闲的时候加载,也就是等当前被使用的模块都加载完空闲下来的时候就去加载, 不用等到用户用到时再加载,这样防止资源过大,等用户用的时候加载过慢

const oBtn = document.querySelector('button');
oBtn.onclick = function() {
    getComponment().then(($div) => {
        document.body.appendChild($div[0]);
    });
};

//方式一 
function getComponment() {
// 返回的事promise函数
    return import('jquery').then(({ default: $ }) => {
        const $div = $('<div>我是div</div>');
        return $div;
    });
}

//方式二 async函数实现
async function getComponment() {
//Prefetching 魔法注释加载
    const { default: $ } = await import(/* webpackPrefetch: true *//* webpackChunkName: "jquery" */'jquery');
    const $div = $('<div>我是div</div>');
    return $div;
}
 

5.4浏览器缓存问题

浏览器有一个特点就是自动缓存网页上的资源, 以便于提升下次访问的速度,但正式因为浏览器的缓存机制, 导致文件内容被修改之后只要文件名称没有发生变化,就不会重新去加载修改之后的资源, 所以刷新网页后显示的还是修改之前的内容

为了解决上面的问题,我们就需要在打包文件的时候给文件名称加上内容的hash值,一旦内发生变化, 内容的hash值就会发生变化, 文件的名称也会发生变化,这样浏览器就会去加载

注意:webpack4.0以后一般使用contenthash哈希值,它是根据某个文件内容生成的哈希值, 只要某个文件内容发生改变,该文件的contenthash就会发生变化,一般使用在 正式环境 打包上线

如何加载设置contenthash哈希值?
我们只需要在webpack.config.js,转化的资源名称后面添加[contenthash:8],其中8是哈希值的长度,通常是 输出的资源,比如:js,图片字体图标

 output: {
        /*
        filename: 指定打包之后的JS文件的名称
        contenthash 添加哈希值
        * */
        filename: 'js/[name].[contenthash:8].js',
        /*
        path: 指定打包之后的文件存储到什么地方
        * */
        path: path.resolve(__dirname, 'bundle')
    },
image.png

5.5模块的全局导入

我们用过npm安装的模块,只能通过import导入模块使用,如果一个模块在每个文件中都需要引入,那这样是需要在每一个文件中都需要import导入的,为了解决这个问题,一次设置全局使用,就需要用到Provide-Plugin插件

Provide-Plugin插件 是系统自带的,不需要安装,只要引入webpack,创建插件就可以

//引入插件
const Webpack = require("webpack");

module.exports = {
 /*
    plugins: 告诉webpack需要新增一些什么样的功能
    * */
    plugins: [
        new CleanWebpackPlugin(),
        new CopyWebpackPlugin([{
            from: './doc',
            to: 'doc'
        }]),
        new MiniCssExtractPlugin({
            filename: 'css/[name].[contenthash:8].css'
        }),
      //设置jquery是全局导入,只需要使用$就可以
        new Webpack.ProvidePlugin({
            $: 'jquery'
        })
    ]
}

5.6 resolve解析规则
  • resolve用于配置导入模块的解析规则

我们在项目开发的过程中,有时候需要导入很多模块,那么在写导入模块的路径,可能是很长,为了简化导入的代码,就需要用到resolve导入模块的解析规则

比如我们在js文件中 导入一个 import 'bootstrap/dist/css/bootstrap.css' css文件,可以通过resolve规则简化,需要在webpack.config.js做一些配置

第一种:那就是通过resolve的alias,起别名,然后直接 import $ from 'bootstrap'; 导入这个模块即可


module.exports = {
           resolve: {
             alias: {
          // 创建 import 或 require 的别名,来确保模块引入变得更简单
           bootstrapcss: 'bootstrap/dist/css/bootstrap.css'
         }
   
    },
}

第二种就是通过 修改入口查找顺序,简化导入代码

module.exports = {
    resolve: {
        // alias: {
        //     // 创建 import 或 require 的别名,来确保模块引入变得更简单
        //     bootstrapcss: 'bootstrap/dist/css/bootstrap.css'
        // }
        // 指定模块入口的查找顺序  的第一种情况
        // mainFields: ['style', 'main']

        // 指定导入模块查找顺序的第二种情况
        extensions: ['.css', '.js', '.joson'],
   // 指定查找范围, 告诉webpack只在node_modules中查找
        modules: ["node_modules"]
    }
}
5.7 Module中 noParse 提升打包速度

我们知道一些第三方库,会有依赖关系,我们在导入模块库的时候,webpack都会分析这个库是否有依赖关系,但是对于一些独立模块是没有依赖关系的,就不需要在webpack在分析,所以需要使用noParseModule中指出,这样可以提升我们的打包速度

module.exports = {
    //告诉webpack如何处理webpack不能够识别的文件,如何转化
       module: {
      //告诉webpack不需要处理分析jquery,因为他是一个独立的第三方库
       noParse: /jquery/,
      }

}
5.8 IgnorePlugin内置插件,忽略指定的目录
  • IgnorePluginwebpack的一个内置插件
  • 用于忽略第三方包指定目录,让指定目录不被打包进去

const Webpack = require('webpack');
module.exports = {
      /*
    plugins: 告诉webpack需要新增一些什么样的功能
    * */
    plugins: [
  
        /*
        以下代码的含义:
        在打包moment这个库的时候, 将整个locale目录都忽略掉
  moment.js是一个处理日期的 第三方库
        * */
        new Webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
    ]

}
5.9dll动态链接库
  • dll动态链接库用于防止重复打包不会发生变化的第三方模块,来提升webpack的打包效率

实现步凑1 : 创建一个配置文件 webpack.config.dll.js,来打包不会发生变化的第三方库

//引入path模块
const path = require('path');
//引入webpack
const Webpakc = require('webpack');

//配置文件
module.exports = {
  //打包模式
    mode: 'production',
//指定打包的入口文件
    entry: {
        vendors: ['jquery', 'lodash']
    },
// output: 指定打包之后的文件输出的路径和输出的文件名称
    output: {
        //name是入口的 对应的key 就是 vendors
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dll'),
        library: '[name]'
    },
//添加插件
    plugins:[
        /*
        DllPlugin作用:
        在打包第三方库的时候生成一个清单文件
        * */
        new Webpakc.DllPlugin({
            name: '[name]',
            path: path.resolve(__dirname, 'dll/[name].manifest.json')
        })
    ]
};

  1. 使用add-asset-html-webpack-plugin插件,把打包的不变的第三方库,插入到html文件中使用
    注意:add-asset-html-webpack-plugin插件是HtmlWebpackPlugin插件的扩展,需要在HtmlWebpackPlugin后创建

2.1 我们在webpack.config.dll.js文件中配置了打包清单,需要在webpack.config.common.js的配置文件中告诉webapck在打包的时候,不需要在打包清单中的文件

const path = require('path');
const Webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
     plugins: [
        new HtmlWebpackPlugin({
            // 指定打包的模板, 如果不指定会自动生成一个空的
            template: './src/index.html'
        }),
      
        new AddAssetHtmlPlugin({
          //使用这个插件,把路径的中的vendors.dll.js文件,插入到html中
            filepath: path.resolve(__dirname, 'dll/vendors.dll.js')
        }),

        new Webpack.DllReferencePlugin({
          // 告诉webpack清单的文件,不需要在打包
            manifest: path.resolve(__dirname, 'dll/vendors.manifest.json')
        })
     
    ]


}

  1. 需要在package.json文件中,添加脚本script编译,收到打包一次
"scripts": {
    "start": "npx webpack-dev-server --config webpack.config.dev.js",
    "dev": "npx webpack --config webpack.config.dev.js",
    "prod": "npx webpack --config webpack.config.prod.js",
    "dll": "npx webpack --config webpack.config.dll.js"
  },

注意上面的webpack.config.dll.js文件中,我们把jquery,lodash打包合成了一个vendors .dll.js文件,但是有时在开发工程的时候,不需要这样,希望单独的打包成独立的文件,那么就如下做法,entry对应的文件单独分离开来

const path = require('path');
const Webpack = require('webpack');

module.exports = {
    mode: 'production',
    entry: {
        jquery: ['jquery'],
        lodash: ['lodash'],
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dll'),
        library: '[name]'
    },
    plugins:[
        /*
        DllPlugin作用:
        在打包第三方库的时候生成一个清单文件
        * */
        new Webpack.DllPlugin({
            name: '[name]', // 注意这个名称必须和library名称一致
            path: path.resolve(__dirname, 'dll/[name].manifest.json')
        })
    ]
};

image.png

那么在对应的webpack.config.commoc.js文件中,要动态的生成 AddAssetHtmlPlugin对应的路径

const path = require('path');
const Webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const fs = require('fs');
const plugins = [
    new HtmlWebpackPlugin({
        // 指定打包的模板, 如果不指定会自动生成一个空的
        template: './src/index.html'
    })
];

 //动态生成路径
const dllPath = path.resolve(__dirname, 'dll');
const files = fs.readdirSync(dllPath);

files.forEach(function (file) {
   if(file.endsWith(".js")){
       plugins.push(new AddAssetHtmlPlugin({
           filepath: path.resolve(__dirname, 'dll', file)
       }));
   }else if(file.endsWith(".json")){
       plugins.push(new Webpack.DllReferencePlugin({
           manifest: path.resolve(__dirname, 'dll', file)
       }));
   }
});


module.exports = {
    //配置插件
    plugins:  plugins
}



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343