webapck 配置项详情 webpack 知识点

119 阅读7分钟

webpack

webpack 核心配置

  1. Entry

    • 入口(Entry)指示webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。

      单入口 sring:指定文件的入口文件,分析构建 。 值为一个路径字符串

      多入口 Array :所有入口文件最终形成一个chunk,输出出去的只有一个bundle文件.(只有在HMR功能中让html 热更新生效)

      多入口object:有多少个入口,最终输出多少个bundle,

  2. Output

    • 输出(Output)指示webpack打包后资源 bundles 输出到哪里去,以及如何命名。

      filename:文件名称,指定名称+目录

      path:输出文件目录,将来所有文件资源输出的公共目录

      pubilicPath:所有资源引入公共路径前缀

      chunkFilename:非入口chunk的名称

      library:整个库向外暴露的变量名

      libraryTarget:变量名添加到那个上 browser,node ,commonjs

  3. loader

    • loader 让webpack 能够去处理那些非JavaScript 文件(webpack 本身只理解JavaScript)

      exclude:排除某些不执行

      include:只检查指定目录下的文件

      enforce:是否优先

      loader:单loader 使用

      options:选择属性可以修改loader 的用途

      oneof: oneof 下的配置只会生效一个

  4. Plugins

    • 插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。
  5. Mode

    • 模式(Mode) 指示webpack 使用相对应的模式的配置
  6. resolve

    • 解析模块的规则

      alias: 配置解析模块路径别名:优点简写路径,缺点路径没有提示

      extensions:配置省略文件路径的后缀名

      modules:告诉webpack 解析模块是去哪里找

  7. devServer

    contentBase 运行代码的目录

    watchContentBase 监视 contentBase 目录下的文件,一旦文件变化就会reload

    watchOptions 忽略文件

    compress 启动gzip压缩

    port 端口号

    host 开启HMR功能

    open 自动打开浏览器

    clientLogLevel 不要显示启动服务器日志信息

    quiet 除了一些基本的启动信息以外,其他内容都不要显示

    overlay 如果错误了,不要全屏提示~

    proxy 动态代理解决跨域问题

选项描述
development会将process.env.NODE_ENV 的值设为 development。
启用 NameChunksPlugins和NameModulesPlugin。
开发模式:让代码在本地调试运行的环境
production会将process.env.NODE_ENV的值设为 production,
启用 FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,
ModuleConcatenationPlugin,
NoEmitOnErrorsPlugin,
OccurrenceOrderPlugin,SideEffectsFlagPlugin
和UglifyJsPlugin
生产环境:让代码优化上线运行的环境。

webpack.config.js

// webpack 要是用commonjs 暴露的方式
const {
    resolve
} = require('path')
module.exports = {
    // webpack配置
    // 入口
    entry: './src/index.js',
    // 输出
    output: {
        // 输出的文件名
        filename: 'build.js',
        // 输出的文件路径
        // __dirname nodejs 中的变量 ,代表当前文件的绝对路径
        path: resolve(__dirname, 'build')
    },
    // loader 需要加载的配置
    module: {
        rules: [
            //详细的loader
            {
                //test匹配那些文件,使用的正则表达式的方式.
                test: /\.css$/,
                use: [
                    // use 数组中loader 执行顺序为 右到左的方式,依次执行
                    // style-loader 创建style 标签,将js的样式资源插入到head中生效
                    //css-loader 将css文件变成commonjs模块 加载到js中,里面的内容是样式字符串
                    'style-loader', 'css-loader'
                ]
            },
            {
                test:/\.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            }
        ]
    },
    // plugins 的配置
    plugins: [],
    // 模式
    mode: 'development'
}

webpack plugins 使用 (HtmlWebpackPlugin)

​ html-webpack-plugin 之前 需要 导入该模块

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exprots ={
    plugins:[
        new HtmlWebpackPlugin({
            // 辅助当前目录下的index.html 并且自动引入打包输出的所有资源(JS/CSS)
            template:'选择文件模板'
        })
    ]
}

webpack 打包其他资源(其他资源为 除了 html/css/js 都为其他资源)

    module: {
        rules: [
        // 打包除了其他资源(除了HTML/CSS/JS资源以外的资源)
         {
            exclude:/\.(css|js|html)$/,
            loader:'file-loader'
        }]
    },

webpack devServer (自动保存更新服务器)

​ 使用devServer 首先安装webpack-dev-server 模块

    devServer:{
        // 项目构建后的路径
        contentBase:resolve(__dirname,'build'),
        // 是否使用gzip压缩
        compress:true,
        // 设置端口号
        port:3000,
        // 是否自动打开浏览器
        open:true
         
    }

webpack 单独打包CSS样式 (css 会以link 的形式 引入到html中)

  • 使用的mini-css-extract-plugin 这个插件来进行处理
const {
    resolve
} = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    // 入口文件 指定主文件
    entry: './src/js/index.js',
    // 输出:
    output: {
        filename: 'js/built.js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [{
            test: /\.css$/,
            // loader: ExtractTextWebpackPlugin.extract('style-loader', 'css-loader')
            use: [
                    // style-loader 是将js中的css 样式以style 标签的形式引入
                    // 'style-loader',
                    //使用 MiniCssExtractPlugin  来进行单独打包css
                    MiniCssExtractPlugin.loader,
                    // css-loader:是将css样式 转换成js
                    'css-loader'
                ]
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin({
            // 给输出的css 重命名
            filename:'css/build.css'
        })
    ],
    mode: 'development'
}

webpack css样式兼容性

  • 需要引入两个模块 postcss-loader postcss-preset-env
module.exports ={
    module: {
            rules: [{
                test: /\.css$/,
                use: [

                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    // 配置postcss-loader
                    /*
                        帮助postcss找到package.js 中的browserslist 里面的配置,通过配置加载指定的css兼容样式。
                    */
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            plugins: () => [
                                // 使用post-css的插件
                                require('postcss-preset-env')
                            ]
                        }
                    }
                ]
            }]
        },
    }
  • package.js 配置 browserslist属性
  "browserslist":{
    "development":[
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production":[
      ">0.1%",
      "not dead",
      "not op_mini all"
    ]
  }

webpack 压缩css

  • webpack中压缩css 需要引入一个插件:optimize-css-assets-webpack-plugin
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

module.exports ={
    plugins:[
        //使用压缩css 样式插件
        new OptimizeCssAssetsWebpackPlugin();
    ]
}

webpack 使用eslint 语法检查

  • webpack 使用eslint 需要在package.js进行配置
  "eslintConfig":{
    "extends":"airbnb-base"
  }
  • 使用eslint 需要在添加一个loader进行语法规范检查
 rules: [
      {
        // 使用的eslint 语法检查,需要导入 eslint-loader 和 的eslint
        // 使用 eslint-config-airbnb-base 要引入 eslint 和  eslint-plugin-import
        // 想要使用eslint 对代码进行管理需要在package.js中引入eslint
        test: /\.js$/,
        exclude: 'node_modules',
        enforce:'pro',
        loader: 'eslint-loader',
        options: {
          fix: true,
            // eslint-disable-next-line linebreak-style
        },
      },
    ],

webapck 中JS代码兼容性处理

  • js兼容性处理 babel-loader @babel/core
    • 1.基本js兼容性处理 -> @babel/preset-env
      • 问题:只能处理基本语法,无法对promise 和高级语法无法兼容
    • 2.全部js兼容性处理 -> @babel/polyfill
      • 问题:我们只需要解决部分兼容问题,但是将所有的兼容性处理代码全部引入,体积太大~
    • 3.需要做兼容性处理的就做:按需加载 -> @core-js
rules: [
            /*
            js兼容性处理 babel-loader @babel/core
                * 1.基本js兼容性处理   -> @babel/preset-env
                * 问题:只能处理基本语法,无法对promise 和高级语法无法兼容
                * 2.全部js兼容性处理  -> @babel/polyfill
                * 问题:我们只需要解决部分兼容问题,但是将所有的兼容性处理代码全部引入,体积太大~
                * 3.需要做兼容性处理的就做:按需加载 -> @core-js
            */
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        ['@babel/preset-env', {
                            // 按需加载
                            useBuiltIns: 'usage',
                            // 指定corejs 版本 为3个版本
                            corejs: {
                                version: 3
                            },
                            // 指定兼容性需要做到那个浏览器
                            targets: {
                                chrome: '60',
                                firefox: '60',
                                ie: '9',
                                safari: '10',
                                edge: '17'
                            }
                        }]
                    ]
                }
            }
        ]

webpack HMR模块热替换

hot module replacement 模块热替换

作用: 一个模块发生变化,只会重新打包这一个模块,而不是打包所有模块,极大提升构建速度

css文件:可以使用HMR功能呢,因为style-loader 已经实现了

js文件:默认不能使用HMR功能,需要修改js代码,添加支持HMR更新的代码

注意:HMR功能只对JS的处理,只能处理非入口js文件和其他文件

if(module.hot){
    module.hot.accept('./print.js',function(){ //告诉 webpack 接受热替换的模块
     console.log('Accepting the updated printMe module!')   
    })
}

html文件:默认不会使用HMR功能,同事会导致问题:HTML文件不能热更新了

解决:修改entry入口,将html文件引入

webapck sourecemap

source-map:会生成map格式的文件,里面包含映射关系

inline-source-map:不会生产map格式的文件,包含映射关系的代码会放在打包后的代码中

注意:使用iline-source-map 的时候,map文件就会变成一个很长的base64的字符串 被放在main.js的底部和source-map的区别是直接 map文件打包到了main文件内

cheap-inline-source-map:cheap有两种作用,一是将错误只定位到行,不定位到列。二是映射业务代码,不映射loader和第三方库等。会提升打包构建速度。

cheap-module-inline-source-map:业务代码,loader和第三方库代码都会映射

eval:打包速度最快的一种方式,针对于比较复杂的代码时 eval 提示出来的内容可能并不是很全面。

最佳实践:

devtool:'cheap-module-source-map'

开发环境:使用 cheap-module-eval-source-map 提示出来的错误比较全,打包速度是比较快的

生产环境:使用cheap-module-source-map

webpack oneof 优化生产环境下打包速度

oneof 下每个loader 只会执行一次

注意:同一种文件类型的文件,oneof 只会执行一次 所以不能再oneof 下处理同一种文件

module.exports ={
    module:{
        rlues:[
            {
                oneof:[
                    {
                        loader
                    }
                ]
            }
        ]
    }
}

webpack cache 缓存

babel 缓存

{
    test:/\.js$/,
    exclude:/node_modules/,
    laoder:"babel-loader",
    options:[
        presets:[
        ['@babel/preset-env',{
        	useBuiltIns:'usage',
        	corejs:{vsersion:3},
		    targets:{
                chrome:'60',
                firefox:'50'
            }
        }]
    ],
	cacheDirectory:true
    ]
}

文件资源缓存

​ hash:每次打包webpack构建时会生成一个唯一的hash值。

​ 问题:因为js和css 同时使用一个hash值,如果重新打包,会导致所有缓存失效,

​ chunkhash:根据chunkhash生成的hash值,如果打包来源与同一个chunk,那么hash值就一样

​ 问题:js和css 值还是一样的,因为css 是在js中引入的,所以同属于一个chunk

​ contenthash:根据文件的内容生成的hash值。不同文件hash值,肯定不一样

webpack tree shaking

​ 前提:1,必须使用es6模块化 2.开始production 环境

​ 作用:减少代码的体积

​ 在package.js文件中配置

​ "sideEffects":false 所有代码都没有副作用(都可以进行tree shaking)

​ 问题:可能会把css / @babel/polyfill (副作用) 文件干掉

​ "sideEffects":["*.css"," *.less"]

webpack split code 代码分割

第一种方法:配置多入口,多页面

​ 注意:如果有公共代码块,那么打包之后的两个bundle里面都会包含重复的模块,以及不够灵活,不能被webpack通过splitChunks的规则灵活地优化。

const path = require('path');

module.exports = {
  mode: 'development',
  entry: {
    index: './src/index.js',
    another: './src/another-module.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

第二种方法:optimization.splitChunks (entry 单入口)

​ 可以将node_modules 中的代码单独打包一个chunk最终输出,

​ 自动分析多入口chunk中,有没有公共文件。如果有会打包成一个chunk

optimization:{
    splitChunks:{
        chunks:'all'
    }
}

第三种方法:import() 动态导入 (entry 单入口)

​ Dynamic Imports:动态加载,在函数中使用import()语法,webpack使用SplitChunk将import()加载的module分割为一个单独的chunk,并在函数执行时加载改chunk对应的JS文件。

import ('./test').then(({mothod1,mothod2})=>{
    console.log(mothod1(2,4));
}).catch(()=>{
    console.log("文件加载失败了。");
})

webpack 懒加载 和预加载

​ 懒加载:当文件需要的时候在加载。

import Test from './test';
document.getElementById('btn').onclick = funcation (){
    import('./test').then((Test) => {
        console.log(Test.mul(4, 5))
    }).catch(() => {
    })
}

预加载:(当主代码加载完成后,预加载引入异步代码,等到异步代码触发时,会再次加载,但此时缓存中已经加载过,所以执行效率会变高)

​ 注意:当使用预加载的时候 需要加上/* webpackPrefetch:true */

import Test from './test';
document.getElementById('btn').onclick = funcation (){
    import(/* webpackPrefetch:true */'./test').then((Test) => {
        console.log(Test.mul(4, 5))
    }).catch(() => {
    })
}

Webpack PWA (渐进式网络程序)

​ 添加 workbox-webpack-plugin 插件,并调整webpack.config.js配置

new WorkboxWebapckPlguin.GenerateSW({
     // clientsClaim:让ServiceWorkbox 快速启动
     // skipWaiting:删除旧的ServiceWorkbox
     clientsClaim:true,
     skipWaiting:true 
})

​ 注册workbox在主入口中

if('serviceWorker' in navigator){
    window.addEventListener('load',()=>{
        navigator.serviceWorker.register('/service-worker.js').then(()=>{
            console.log("sw注册成功了")
        }).catch((registrationError)=>{
            console.log("sw注册失败了",registrationError)
        })
    })
}

thread-loader (多进程打包)

使用thread-loader 对babel -loader 进行多线程打包
{
    test:/\.js$/,
    exclude:/node_modules/,
    use:[
        {
            //开启多线程打包
            loader:'thread-loader',
            options:{
                workers:2  //两个进程
            }
        }
    ]
}

externals (拒绝打包)

​ 在webpack.config.js 文件

externals:{
    jquery:'jQurey'
}

dllPlugin 打包

DLLPluginDLLReferencePlugin 用某种方法实现了拆分 bundles,同时还大大提升了构建的速度。

context (optional):manifest 文件中请求上下文(context)默认值为webpack的上下文(context)

name :暴露出去的DLL的函数名

path:manifest.json文件的绝对路径

 new webpack.DllPlugin({
            // 暴露出的dll函数名 
            name:'[name]_[hash]', 
            // manifest.json 文件的绝对路径(输出文件)
            path:resolve(__dirname,'dll/manifest.json')
  })