webpack5学习笔记

54 阅读3分钟

基础

使用原因

1.受限于js文件加载顺序从上往下,可能导致加载失败
2.作用域问题,挂载在window上变量过多,可能导致冲突(可使用立即调用函数表达式IIFE创建独立作用域)

(function(){
   var name = '123' 
})()
console.log(name)

3.代码拆分,(依赖ES6实现)使用export default XX 来暴露模块,import XX form XX 来引入模块, 需要在script标签上添加 type="module" 属性

安装webpack

1.安装node
2.全局安装:npm i webpack webpack-cli --global(不建议,易产生版本不一致问题)
3.项目下安装:npm install webpack webpack-cli --save-dev
4.npm init -y生成package.json
5.webpack -v查看版本

运行webpack

1.全局:终端输入webpack,生成dist文件夹; webpack -status -datailed查看打包详情
2.当前目录:npx webpack;可在之后加上--help查看其他指令

配置webpack

在当前目录新建名为webpack.config.js的文件

const path=require('path')

module.exports={
        entry:'/src/index.js'  //定义入口文件
        output:{               //打包文件
            filename:'bundle.js',
            path:path.resolve(__dirname,'./dist')
        },
        mode:'development',
        devtool:'inline-source-map'
}

关于devtool:
1.7种SourceMap模式
2.webpack文档

插件

HtmlWebpackPlugin

安装:npm install html-webpack-plugin -D

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

module.exports={
  entry:'./src/index.js',
  output:{
    filename:'bundle.js',
    path:path.resolve(__dirname,'./dist')
  },
  mode:'development',
  devtool: 'inline-source-map' ,
  plugins:[
    new HtmlWebpackPlugin({
        template:'./index.html',  //参考的html
        filename:'app.html',   //生成文件名
        inject:'body'   //指定script语句插入到body中
      })
  ],
}

webpack-dev-server

可以直接通过npx webpack --watch命令实现编译时自动检测文件变化,但需要手动刷新浏览器
使用插件使得文件打包后的本地代码实时更新,提高webpack开发效率
安装: npm install webpack-dev-server -D
配置:

module.exports={
	...
    devServer:{
      static:'./dist'  //server的根目录,物理路径
    },
}

要先执行编译后再执行:npx webpack-dev-server --watchnpx webpack servenpx webpack-dev-server --open(直接在浏览器打开)

资源模块

module: {
    rules: [
        {
            test: /\.png$/,     //正则表达式
            type: "asset/resource",     //发送一个单独的文件并导出 URL
            generator: {
                filename: 'images/test.png'      //第二种方法,会覆盖output中的名字设置
            }
        },
        {
            test: /\.svg$/,
            type: 'asset/inline',       //导出一个资源的 data URI
        },
        {
            test: /\.txt$/,
            type: 'asset.source',   //导出资源的源代码
        },
        {
            test: /\.jpg$/,
            type: 'asset', //在导出一个 data URI 和发送一个单独的文件之间自动选择
            parser: {
                dataUrlCondition: {
                    maxSize: 4 * 1024   //默认值为4k,大于4k发送一个单独的文件,小于导出dataUrl
                }
            }
        }
    ]
}

loader

cssloader

分别安装loader后修改配置:

module: {
    rules: [
        {
            test: /\.(css|less)$/,
            use: ['style-loader','css-loader','less-loader']    //从后往前链式解析
        }
    ]
}

抽离与压缩css

抽离:执行npm install mini-css-extract-plugin安装插件(必须在webpack5环境下)

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

plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html",
            filename: "app.html",
            inject: "body"
        }),
        new MiniCssExtractPlugin({
            filename: "styles/[contenthash].css"
        })
    ],
    module: {
        rules: [
            {
                test: /\.(css|less)$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']   
            }
        ]
    }

压缩: 执行npm install css-minimizer-webpack-plugin安装插件

const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
    mode: "production",    //需改为生产模式
    optimization: {
        minimizer: [
            new CssMinimizerWebpackPlugin()
        ]
    }
}

代码分离

项目中若存在多个入口文件时,则需要代码分离;若存在多个模块共用的代码时,也需要分离代码来防止重复打包。

入口起点:

    entry:{
        index:'./src/index.js',
        another:'./src/another-module.js'
    },
    output:{
          filename:'[name].bundle.js',
          path:path.resolve(__dirname,'./dist'),
          clean:true,
          assetModuleFilename:'images/[contenthash][ext]',
    },

问题:多入口文件会导致存在相同文件时,重复打包至各自模块

entry依赖:

Entry dependencies

例如当两个模块共有lodash时,会抽离出来并取名为lodash。

     entry:{
          index:{
            import:'./src/index.js',
            dependOn:'shared'
          },
          another:{
            import:'./src/another-module.js',
            dependOn:'shared'
          },
          shared:'lodash'
          index:'./src/index.js',
          another:'./src/another-module.js'
    }
SplitChunksPlugin

配置时依旧可以采用独立命名

    entry:{
        index:'./src/index.js',
        another:'./src/another-module.js'
    }

在 optimization 优化配置项中添加 splitChunks

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

动态引入

通过import实现动态引入,且不影响其他模块抽离方式

假设async-module.js 为功能模块

function getComponent(){
    return import('lodash').then(({default:_})=>{
        const element = document.createElement('div')
        element.innerHTML = _.join(['hello','webpack'],' ')
        return element
    })
}
getComponent().then((element)=>{
    document.body.appendChild(element)
})

在其他文件中引入import './async-module.js'

懒加载

可以加快应用的初始载入速度,减轻总体积,没有使用到的模块先不加载,使用时再进行加载

button.addEventListener('click',()=>{
    //加上注释 webpackChunkName:'模块名' 后,可以定义打包后的模块名  
    import(/* webpackChunkName:'math' */'./math.js').then(({add})=>{
    console.log(add(4,5));
    })
})
预获取/预加载模块

在声明import时,使用下面这些内置指令,可以让webpack输出“resource hint(资源提示)”,来告知浏览器:

prefetch(预获取):将来某些导航下可能需要的资源 ,即在浏览器网络空闲时再获取资源

preload(预加载):当前导航下可能需要资源,和懒加载效果类似

const button = document.createElement('button')
button.textContent = '点击执行加法运算'
button.addEventListener('click',()=>{
    import(/* webpackChunkName:'math',webpackPrefetch:true*/'./math.js').then(({add})=>{
    console.log(add(4,5));
    })
})
document.body.appendChild(button)