webpack学习以及 webpack从0-1搭建vue3+ts工程

40 阅读4分钟

动态导入

import().then(res=>{}) ///动态导入

缓存

1.hash缓存 利用contentHash 内容不便 hash值不便的原则进行缓存。 2.利用optizimation.splitChunks.cacheGroups进行缓存(推荐)。

公共路径

```js
publicPath:"",//当你不清楚publicPath时 你可以设置成auto webpack 会自动的根据import.meta.url,document.currentScript.src,script.src,window.location.origin 来设置

plugins:[
  new webpack.DefinePlugin({  //安全的使用环境变量
    'process.env':{
      NODE_ENV:"production"
    }
  })
]
```

环境变量

```js
plugins:[
  new webpack.DefinePlugin({
    'process.env':{
      NODE_ENV:"production"
    }
  })
]
```

抽离公共代码

    optimization:{
        splitChunks:{  //默认抽离的是node_modules下的代码和 公用的代码
            chunks:"all",
            cacheGroups:{
                vendors:{
                    name:"vendors",
                    priority:1,
                        test:/[\\/]node_modules[\\/]/,
                        minSize:0,
                        minChunks:1,
                        enforce:true
                },
                default:{
                    name:"common",
                    priority:0,
                    minSize:0,
                    minChunks:2,
                    enforce:true
                }
            }
        }
    }

懒加载

    import(/*webpackChunkName:"index"*/"./index").then(res=>{})

预加载


    import(/*webpackChunkName:"index"*/"./index").then(res=>{})
    import(/*webpackPrefetch:true*/"./index").then(res=>{})

高级应用

devServer

devServer:{
    port:8080,
       open:true,
       hot:true,//开启热更新
       hotOnly:true, //更新失败后是否 重新刷新
       compress:true, //是否开启gzip压缩
       historyApiFallback:true, //解决单页面刷新问题
       liverReload:true,
       // https:true,//开启https 
     
       headers:{
         //请求头部添加标识
           "X-Custom-Header":"yes"
       },
       


       proxy:{//解决跨域问题
           "/api":{
               target:"http://localhost:3000",
               pathRewrite:{
                   "^/api":""
               }
           }
       }
   }

热更新

if(module.hot){
    module.hot.accept("./index.js",()=>{
        console.log("index.js更新了")
    })
}

webpack模块和解析原理

webpack天生支持的模块有 ECMAScript模块,commonjs模块 AMD模块,assets模块,WebAssemly模块 webpack打包编译的过程其实可以理解成一个promise的过程状态分为打包前 打包中 打包后,每次打包都会创建一个compiler的对象。 所有的模块解析 都是通过compiler对象的Resolvers属性来完成的 Resolvers模块解析 是基于enhanced-resolve这个包 实现的。

webpack的模块解析规则

1.绝对路径 绝对路径的话webpack 会直接使用这个路径,不会进行任何的解析 2.相对路径 相对路径webpack会先将相对路径转换成绝对路径,然后在进行模块解析

 //使用resolve 将相对路径解析成绝对路径
 path.resolve(__dirname,"./index.js") 

3.模块路径 模块路径也就是我们配置的resolve.modules属性,webpack会先将模块路径转换成绝对路径,然后在进行模块解析 默认模块路径是node_modules 我们可以通过resolve.alias来修改模块路径

 resolve.alias:{
     "@":path.resolve(__dirname,"./src")
 }

模块路径的优先级高于别名路径

resolve

在resolve中设置如何被解析

resolve: {
alias: { //定义别名
"@utils": path.resolve(__dirname, 'src/utils/')
},
extensions: ['.js', '.json', '.wasm'] //设置解析文件的规则 
modules: [path.resolve(__dirname, 'src'), 'node_modules'] //设置模块的查找路径
}
外部扩展

我们将第三方库抽离或者将自己的库抽离出来通过externals属性来设置

externals: {
  lodash: {
    commonjs: 'lodash',
    commonjs2: 'lodash',
    amd: 'lodash',
    root: '_'
  }
}
然后再index.html 中通过cdn 或者其他外链的方式将 第三方库引入 以减少打包中的包体积
打包分析
```js
npm install webpack-bundle-analyzer -D
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins:[
    new BundleAnalyzerPlugin()
]
```

扩展功能

PostCSS和css 模块

postcss 是通过js工具将转换css代码的工具 可以通过postcss为css添加浏览器前缀,解析嵌套语法等

  npm install postcss-loader postcss-preset-env -D
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[
                  "style-loader",
                  "css-loader",
                  "postcss-loader"
                 
              ]
          }
      ]
  }

  // postcss.config.js
 module.exports = {
plugins: [
require('autoprefixer'),//自动添加 浏览器的兼容前缀
require('postcss-nested') //提供编写嵌套的样式语法
]
}

//解决多人开发环境下的样式冲突
module:{
 rules:[
          {
              test:/\.css$/,
              use:[
                  "style-loader",
                   {
                       loader:"css-loader",
                       options:{
                           modules:true //开启css 模块化
                            localIdentName: "[local]--[hash:base64:5]",//设置css 模块化 的命名规则
                       }
                   },
                  "postcss-loader"
                 
              ]
                   },
                  "postcss-loader"
                 
              ]
          }
      ]
}


tree-shaking

tree-shaking 是一种通过消除多余代码,减小代码体积,提高程序性能的技术。 但tree-shaking不是对于所有的文件都有效果 如一下的文件就没有效果

import {add} from './math.js'
import {add as add2} from './math.js'
console.log(add(1,2))
console.log(add2(1,2))

因此我们可以通过设置再 package.json 中设置sideEffects的方式 进行开始或者关闭以及制定list 外的文件进行tree-shaking

sideEffects:false //默认值
sideEffects:true //开启所有文件的tree-shaking
sideEffects:['*.css'] //开启所有css文件的tree-shaking
sideEffects:['*.css','./dir'] //开启所有css文件的tree-shaking 以及./dir 下的所有文件

shimming 预置依赖

shimming 是指在代码中预置一些依赖,以便在代码运行时能够正常使用这些依赖。

shimming 预置全局变量

通常我们使用第三方的库或者使用一些垫片的时候 并不是针对于全部的情况,而是针对于某个环境,因此我们需要预置全局变量 例如我们使用jquery的时候,我们并不需要在每个文件中都引入jquery,只需要在入口文件中引入jquery即可,然后通过window.jQuery来使用jquery 因此我们可以通过设置webpack.ProvidePlugin来预置全局变量

  //webpack.config.js
  const webpack = require('webpack')
  module.exports = {
      plugins:[
          new webpack.ProvidePlugin({
              $:"jquery",
              join: ['lodash', 'join'], //按需引入 某些包中特定的模块 其余的模块则通过tree-shaking进行删除
           })
           ]
   }

当文件中使用了预设值的全局变量后 webpack才会将package 构建到使用它的模块中。

模块联邦

模块联邦是一种模块化解决方案,它允许在不同的模块之间共享模块。

基本使用

1.系统a

    // 导出模块
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const {
    ModuleFederationPlugin
    } = require('webpack').container
    module.exports = {
        mode: 'production',
        entry: './src/index.js',
        plugins: [
            new HtmlWebpackPlugin(),
            new ModuleFederationPlugin({
                // 模块联邦名字
                name: 'nav',
                // 外部访问的资源名字
                filename: 'remoteEntry.js',
                // 引用的外部资源列表
                remotes: {},
                // 暴露给外部资源列表
                exposes: {
                    './Header': './src/Header.js',
                },
                // 共享模块,如lodash
                shared: {},
            }),
        ]
    }

2.系统b

    // 导出模块
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const {
    ModuleFederationPlugin
    } = require('webpack').container
    module.exports = {
        mode: 'production',
        entry: './src/index.js',
        plugins: [
            new HtmlWebpackPlugin(),
            new ModuleFederationPlugin({
                // 模块联邦名字
                name: 'home',
                // 外部访问的资源名字
                filename: 'remoteEntry.js',
                // 引用的外部资源列表
                remotes: {
                    home:'nav@http://localhost:8000/remoteEntry.js'  //使用系统a 的模块
                },
                // 暴露给外部资源列表
                exposes: {
                    './Header': './src/Header.js', //抛出自己的模块
                },
                // 共享模块,如lodash
                shared: {},
            })
        ]
    }
       
    

b系统中的使用

    import('home/Header')
    .then(module => {
        module.default()
    })
模块联邦的配置
// webpack.config.js
  // 导出模块
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const {
    ModuleFederationPlugin
    } = require('webpack').container
    module.exports = {
        mode: 'production',
        entry: './src/index.js',
        plugins: [
            new HtmlWebpackPlugin(),
            new ModuleFederationPlugin({
                // 模块联邦名字
                name: 'nav',
                // 外部访问的资源名字
                filename: 'remoteEntry.js',
                // 引用的外部资源列表
                remotes: {},
                // 暴露给外部资源列表
                exposes: {
                    './Header': './src/Header.js',
                },
                // 共享模块,如lodash
                shared: {},
            }),
        ]
    }

性能优化

利用include和exclude缩小范围

include 和 exclude 都是用来缩小范围,但是include 只针对单一的文件,而exclude 则可以针对多个文件进行排除

module: {
rules: [
        {
            test: /\.js$/,
            include: path.resolve(__dirname, 'src'),//通过include 缩小范围
            exclude: /node_modules/,//通过exclude 排除范围
            use: {
                loader: 'babel-loader',

            },
        ],
        },

解析

  • 减少resolve.modules,resolve.extensions,resolve.descriptionsFiels,resolve.mainFiles 中的条目数量,因为这些会增加文件系统调用的次数。
  • 如果不使用symlinks(npm link等)建议resolve.symlinks:false

缓存

将cache 类型设置为内存或者文件系统

//webpack.config.js

cache: {
    type: 'memory'
  }

使用dll加速构建

worker池

利用thread-loader 将非常消耗资源的loader 分流给thread-loader

注意:不能使用太多的worker y因为node.js的runtime和loader都启动了开销。主子进程之间模块传输也是非常消耗资源的。

最后 附上webpack从0-1搭建的vue3+ts的工程化项目地址 github.com/jiakaiqiang…