webpack5学习笔记

代码哈士奇
• 阅读 1290

我的前端之路笔记

cdn资源 cdn资源

webpack官网

webpack插件

webpack笔记

解决作用域问题 快速执行函数

;(function(){ ..... })

解决代码拆分问题 node commonjs 模块化

解决浏览器支持问题 requirejs

想要主js调用别的js要在主js前引入

hello.js export hello()

main.js hello()

import hello.js import main.js

安装webpack

先安装node

然后安装webpack webpack-cli 全局安装(不推荐,会锁定版本)

npm install webpack webpack-cli --global

本地安装

npm init 
npm install webpack webpack-cli --save-dev 

cmd cls清屏

webpack打包

webpack

webpack --stats detailed 查看详细打包信息

npx牛逼

配置入口文件(指令不如文件配置不可保存)

webpack --entry xxx

加 --mode production生产环境

配置出口

output

文件配置

webpack.config.js文件

绝对路径 使用 require('path')

path.resolve(__dirname,'xxx')

module.exports = {
    entry:'',

    output:{
        filename: '',
        path: '结对路径''
    }


}

自动引入资源

插件-html-webpack-plugin

npm install html-webpack-plugin

引入

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

在根{}下


plugins:[
    new HtmlWebpackPlugin()
]

配置HtmlWebpackPlugin
new HtmlWebpackPlugin({
    template: './index.html', 模板文件
    filename: 'app.html', 生成文件名
    inject: 'body' 在哪个标签引入
})

清理dist(清理旧的打包)

在output选项里面

output:{
        filename: '',
        path: '结对路径'',
        clean: true
    }

搭建开发环境

mode选项

定位错误

更好显示代码定位错误

devtool: 'inline-source-map',

监听代码变化

webpack --watch

使用 webpack-dev-server

npm install webpack-dev-server

加-D 在本地开发环境运行

在 配置文件中

devServer: {
    devServer: {
        static: './dist'  //注意这里的./dist是路径
    }
}

在控制台 webpack-dev-server

资源模块

module: {
        rules: [
            {
                test: /\.png$/,
                type: 'asset/resource'
            }
        ]
    }

在js 文件中引入

import imgsrc from './assets/img-1.png'

const img = document.createElement('img') 创建一个照片元素
img.src = imgsrc 添加路径
document.body.appendChild(img) 将照片添加进页面

webpack-dev-server --open 加--open 默认打开

在output中定义导出路径以及名字

output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname,'./dist'),
        clean: true,
        assetModuleFilename: 'images/test.png'
    },

assetModuleFilename: 'images/[contenthash].png' [contenthash]可自动根据hash来生成文件名

assetModuleFilename: 'images/[contenthash][ext]' [contenthash]可自动根据hash来生成文件名以及扩展名

若在module rules generator配置 则generator高于output

inline配置资源 使图片变成base64资源

使图片变成base64资源

test: /\.svg$/,
type: 'asset/inline'

配置source

test: /\.txt$/,
type: 'asset/source

配置asset

test: /\.jpg$/,
type: 'asset'

自动选择url还是文件base64 一般小于8k会生成base64

可通过追加 parser 来控制

test: /\.jpg$/,
type: 'asset',
parser: {
    dataUrlCondition: {
        maxSize: 4*1024  //默认大小4*1024 
    }
}

loader使用

安装css-loader以及style-loader

执行

npm install css-loader -D

npm install style-loader -D

配置

{
    test: /\.css$/,
    use: ['style-loader','css-loader']
}

在index.js引入 import './style.css'

先执行css-loader再执行style-loader

安装配置less-loader css-loader

npm install less-loader less -D

配置

{
    test: /\.(css|less)$/,
    use: ['style-loader','css-loader','less-loader']
}

在index.js引入 import './style.less'

抽离和压缩css

安装插件

npm install mini-css-extract-plugin -D

在webpack.js引入

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

在plugins中添加

new MiniCssExtract()

配置

{
    test: /\.(css|less)$/,
    use: [MiniCssExtract.loader','css-loader','less-loader']
}

更换style-loader为MiniCssExtract.loader

style-loader作用是将css连接到页面 而为了抽离改为MiniCssExtract.loader

自定义生成的文件名

new MiniCssExtract({ filename: 'styles/[contenthash].css' })

压缩

安装插件

npm install css-minimizer-webpack-plugin -D

引入

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

在优化配置中配置

webpack配置根级

optimization: {
    minimizer: [
        new CssMinimizerPlugin()
    ]
}

注意配置此项之后 代码压缩会失效 需要单独配置terser

且mode更换为生产环境

mode: 'production',

加载images图像

图片优先级

.block-bg{ background-image: url(./assets/webpack-logo.svg) !important; }

!important 使优先级最高

加载字体

配置webpack

{
    test: /\.(woff|woff2|eot|ttf|otf)$/,
    type: 'asset/resource'
}

在css文件引入字体文件

@font-face {
    font-family: 'iconfont';
    src: url('./assets/iconfont.ttf');
}

.icon{
    font-family: 'iconfont';
    font-size: 30px;
}

在index.js引入字体

const span = document.createElement('span')

span.classList.add('icon')
span.innerHTML = ''
document.body.appendChild(span)

加载数据 csv-loader xml-loader

安装

npm install csv-loader xml-loader -D

配置

{
    test: /\.(csv|tsv)$/,
    usr: 'csv-loader'
},

{
    test: /\.xml$/,
    usr: 'xml-loader'
}

引入数据在index.js

import Data from './assets/data.xml'
import Notes from './assets/data.csv'

xml转成js对象

csv转换为数组

自定义JSON的parser 例如toml yaml json5

安装

npm install toml yaml json5 -D

配置webpack

const toml = require('toml')
const yaml =require('yaml')
const json5 = require('json5')
{
    test: /\.toml$/,
    type: 'json',
    parser: {
        parse: toml.parse
    }
},

{
    test: /\.yaml$/,
    type: 'json',
    parser: {
        parse: yaml.parse
    }
},

{
    test: /\.json5$/,
    type: 'json',
    parser: {
        parse: json5.parse
    }
}

使用文件

babel-loader

将es6转化为es5

babel-loader:在webpack解析es6 @babel/core:babel核心模块 @babel/preset-env:babel预定,一组babel插件的集合

安装

npm install -D babel-loader @babel/core @babel/preset-env

配置

{ test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }

解决报错regeneratorRuntime

原因 babel生产用于兼容async/await

安装插件 @babel/runtime

npm install @babel/runtime -D

安装插件 @babel/plugin-transform-runtime

npm install @babel/plugin-transform-runtime -D

配置

{
    test: /\.js$/,
    exclude: /node_modules/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['@babel/preset-env'],
            plugins: [
                ['@babel/plugin-transform-runtime']
            ]
        }
    }
}

分离代码

如果有多个入口文件

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

出口的filename: '[name].bundle.js',

但是这样会导致重复打包

避免重复

方案一 共享
entry: {
    index: {
        import: './src/index.js',
        dependOn: 'shared'
    },
    another: {
        import: './src/another-module.js',
        dependOn: 'shared'
    },

    shared: 'lodash'
},
方案二 配置splitChunks

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

动态(异步)导入

如下

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)
})


const button = document.createElement('button')
懒加载
button.textContent = '点击加法运算'
button.addEventListener('click',()=>{
    import(/* webpackChunkName: 'math' */'./math').then(({add})=>{
        console.log(add(4,5))
    })
})

document.body.appendChild(button)

import(/* webpackChunkName: 'math' */'./math')魔法注释 可以设置打包文件名

预加载预获取

prefetch 浏览器空闲时加载

import(/* webpackPrefetch: true */

preload 类似懒加载

import(/* webpackPreload: true */

缓存

输出文件名

filename: '[name].[contenthash].js',

缓存第三方库

optimization: {
    minimizer: [
        new CssMinimizerPlugin()
    ],

    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendors',
                chunks: 'all'
            }
        }
    }
}

js放到一个文件夹

output: { filename: 'scripts/[name].[contenthash].js', ....

开发配置

公共路径

在output中 加入publicPath: 'http://localhost:8080/'

环境变量

module.exports = (env) => { console.log(env) return { webpack配置项 可通过env参数配置 } }

比如

mode: env.production ? 'production' :'development'

webpack --env production

可以传参 a = 1

压缩代码 使用terser-webpack-plugin -D

npm install terser-webpack-plugin -D

使用

optimization: {
        minimizer: [
            new CssMinimizerPlugin(),
            new TerserPlugin()
        ],
...

拆分配置文件

开发环境和生产环境

开发环境

项目根目录新建webpack.config.dev.js 开发环境

修改mode为开发环境

去掉压缩代码以及公共路径或包括缓存

启动

webpack -c ./config/webpack.config.dev.js

-c可用 -config替换

注意生成的文件的路径

生产环境

在config目录下新建 webpack.config.prod.js文件

修改mode为生产环境

删除调试 devtool dev-server

启动

webpack -c ./config/webpack.config.prod.js

额外webpack serve (webpack-dev-server)

可通过 webpack serve -c ./config/webpack.config.dev.js

npm 脚本

在项目根目录下 package.json

{
  "scripts": {
    "start": "npx webpack server -c ./config/webpack.config.dev.js",
    "build": "npx webpack -c ./config/webpack.config.prod.js"
  }
}

忽略性能优化提示

在webpack配置根{}下

performance: { hints: false }

提取公共配置

项目根目录创建webpack.config.common.js文件

去除掉 dev prod中相同配置

合并配置文件 使用webpack-merge

安装

npm install webpack-merge -D

config目录下创建 wenpacj.config.js

const { merge } = require('webpack-merge')

const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')

module.exports = (env) => {
    switch (true) { //可定义key-value判断
        case env.development:
            return merge(commonConfig,developmentConfig)

        case env.production:
            return merge(commonConfig,productionConfig)

        default:
            return new Error('No matching configuration was found')
    }
}

source-map

新建目录 npm init 初始化

安装 npm install webpack webpack-cli webpack-dev-server html-webpack-plugin -D

默认devtool为eval

'source-map'

会生产main.js.map 且生产的main.js注释里会显示sourceUrl main.js.map(显示行列) 且关联 能找到代码问题

'hidden-source-map'

会生产main.js.map 且生产的main.js注释里不会显示sourceUrl main.js.map 且不关联 不能直接找到代码问题

'inline-source-map'

不会生产main.js.map 但生产的main.js注释里会显示sourceUrl main.js.map 且关联 能找到代码问题

'eval-source-map'

不会生成sourcemap文件 而是放到了eval后面 能找到代码问题

'cheap-source-map'

生成map文件 mappings带有行数不带列 能找到代码问题

'cheap-module-source-map' 推荐开发环境

生成map文件 mappings带有行数不带列 带有module的 能找到代码问题

webpack-server 配置

devServer: {
    static: path.resolve(__dirname, './dist'),
    compress: true, //代码压缩 增加gzip
    port: 3000, //端口号
    host: '0.0.0.0', //局域网下可访问

    headers: {
        'X-Access-Token': 'abc123'
    },

    proxy: { //代理配置
        '/api': 'http://localhost:9000'
    },

    // https: true, //开启https
    // {
    //     cacert: './server/pem',
    //     pfx: './server.pfx',
    //     key: './server.key',
    //     cert: './server.crt',
    //     passphrase: 'webpack-dev-server',
    //     requestCert: true
    // }



    http2: true, //开启 http2 https默认自签名

    historyApiFallback: true //历史路径

}

模块热替换和热加载

热替换

hmr在webpack5不需要再繁琐配置 疫情开箱即用

devServer: {
    hot: true    
}

修改js热更新

在app.js

if(module.hot){
    module.hot.accept('./input.js', () => {

    })
}

热加载

devServer: {
    liveReload: true
}

代码规范 eslint

安装
npm i eslint -D
eslint ./src
项目使用
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    mode: 'development',

    entry: './src/app.js',

    module: {
        rules: [
            {
                test: /\.js$/,
                usr: ['babel-loader','eslint-loader'] //先eslint-loader'
            },
        ],
    },

    plugins: [
        new HtmlWebpackPlugin()
    ]
};

开启后可关闭报错

devServer: {
    client: {
        overlay: false //报错覆盖层
    }
}

Githooks--Husky

目的 提交之前检测代码

基本原理

.git/hooks/pre-commit文件

文件内容

eslint ./src
或者
npx eslint ./src
自定义

新建目录 .mygithooks

文件 .mygithooks/pre-commit 内容一样

git 配置

git config core.hooksPath .mygithoosk

Husky
npm husky install -D

huxky install


package.json
 "main": "index.js",
  "scripts": {
    "prepare": "husky install"
  },

在./husky目录下 新增pre-commit文件

记得给予 pre-commit 文件权限 (+x)

写入 npx eslint .src

执行

git add.

git commit -m 'xxx'

如果代码出错会提示

探索webpack原理

解析绝对目录

别名配置

用@ 指向 src

webpack.js

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

优先级配置 默认 js>json

配置

resolve: {
  alias: {
    '@': path.resolve(__dirname,'./src')
  },
  extensions: ['.json','.js','vue']
}

配置外部资源引入(链接引入)

方式一

wepack配置文件

externals: {
  jquery: 'jQuery'
}

在html模板文件里面加入

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
方式二

wepack配置文件

externalsType: 'script', //暴露为script标签
externals: {
  jquery: [
    'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js', //链接
    '$' //暴露标签
  ]
}

依赖图

安装

npm i webpack-bundle-analyzer -D

引入

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

plugins: [
    new BundleAnalyzerPlugin()
  ]

启动webpack serve就会弹出

PostCSS和CSS模块 处理浏览器css兼容问题

安装

npm i postcss-loader -D

npm i autoprefixer -D

配置 webpack

module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      }
    ]
  }

配置 postcss.config.js

在根目录下创建文件

module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

使用

在package.json目录下 根{}

"browserslist": [
    "> 1%", //全球浏览器使用率要大于1%
    "last 2 versions" //每个浏览器的最近两个版本
  ]

插件 postcss-nested

支持比如 body下包括div的 这种

安装

npm i postcss-nested -D

配置postcss.config.js

module.exports = {
  plugins: [
    require('autoprefixer'),
    require('postcss-nested')
  ]
}

开启css模块化

use: ['style-loader',
  {
    loader: 'css-loader',
    options: {
    modules: true  //开启css模块化
  }
 }
, 'postcss-loader'],
exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules

可设置两个配置 一个全局一个局部

如下 在webpack配置

全局配置

{
  test: new RegExp(`^(?!.*\\.global).*\\css`),
    use: ['style-loader',
      {
        loader: 'css-loader',
        options: {
        modules: true  //开启css模块化
      }
     }
    , 'postcss-loader'],
    exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules
}

局部配置

{
  test: new RegExp(`^(.*\\.global).*\\css`),
    use: [
      {
        loader: 'style-loader'
      },
      {
        loader: 'css-loader'
      },
      {
        loader: 'postcss-loader'
      }
      ],
    exclude: [path.resolve(__dirname,'..','node_modules')] //排除外部modules
}

WebWorks

创建一个worker const worker = new Worker(new URL('./work.js',import.meta.url))

接收主线程信息 self.onmessage = () => {

}

主线程接收信息 worker.onmessage = (message) => { console.log(message) }

向主线程发送信息 self.postMessage({ answer: 1111 })

主线程发送信息 worker.postMessage({ question: 'hi,那边的worker线程,请告诉我今天的幸运数字是多少?' })

集成typescript

安装

npm i typescript ts-loader -D

配置 webpack

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
  mode: 'development',
  entry: './src/app.ts',
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },


  resolve: {
    extensions: ['.ts', '.js']  //设置优先ts扩展名
  },

  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist')
  },

  plugins: [
    new HtmlWebpackPlugin()
  ]

}

初始化ts配置文件

tsc --init

修改ts配置

rootDir: "./src"

outDir: "./dist"

ts 使用模块

网址 https://www.typescriptlang.org/dt/search?search=

查询需求模块安装

entry 配置

配置一

entry: [
    './src/app.js',
    './src/app2.js'
  ]

配置二

// entry: [
  //   './src/app.js',
  //   './src/app2.js',
  //   'lodash'
  // ],

  entry: {
    main: ['./src/app2.js', './src/app.js'],
    lodash: 'lodash'
  },

配置三

entry: {
    main: {
      import: ['./src/app2.js', './src/app.js'],
      dependOn: 'lodash' //依赖
    },
    lodash: 'lodash'
  },

index.html模板配置

配置一 基础配置

webpack

 plugins: [
    new HtmlWebpackPlugin({
      title: '多页面应用', //参数
      template: './index.html',
      inject: 'body', //引入js的地方
      chunks: ['main'] //规定引入的js
    })
  ]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>

</body>
</html>

配置二

多页面配置

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

module.exports = {
  mode: 'development',

  // entry: [
  //   './src/app.js',
  //   './src/app2.js',
  //   'lodash'
  // ],

  entry: {
    main: {
      import: ['./src/app2.js', './src/app.js'],
      dependOn: 'lodash',
      filename: 'chanel1/[name].js'
    },
    main2: {
      import: './src/app3.js',
      dependOn: 'lodash',
      filename: 'chanel2/[name].js'
    },
    lodash: {
      import: 'lodash',
      filename: 'common/[name].js'
    }
  },

  output: {
    clean: true
  },


  plugins: [
    new HtmlWebpackPlugin({
      title: '多页面应用',
      template: './index.html',
      inject: 'body',
      filename: 'chanel1/index.html',
      chunks: ['main', 'lodash'],
      publicPath: 'http://www.b.com'
    }),

    new HtmlWebpackPlugin({
      template: './index2.html',
      inject: 'body',
      filename: 'chanel2/index2.html',
      chunks: ['main2', 'lodash'],
      publicPath: 'http://www.a.com'
    })
  ]


}

Tree Shaking

移除未使用模块

配置一 usedExports

es2015特性

但是无法额外模块

配置webpack

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

module.exports = {
  mode: 'production',
  entry: './src/app.js',
  plugins: [
    new HtmlWebpackPlugin()
  ],

  optimization: {
    usedExports :true //此处开启
  }
}

配置二 sideEffects

在packages.json配置

{
  "sideEffects": true, //true都加载 false都不加载
  "sideEffects": ["*.css"], //对于所有的css文件都加载,其它不加载
  "sideEffects": ["*.css", "*.global.js"],//对于所有的css文件以及.global.js文件都加载,其它不加载
}

离线环境下运行

非离线环境下运行

打包完成

安装 http-server

npm i http-server -D

配置 packages.json

"scripts": {
    "start": "http-server dist"
  },

使webpack serve 运行时变动打包而不是内存

webpack 配置

devServer: {
    devMiddleware: {
      writeToDisk: true
    }
  }

添加workbox 实现pwa

安装

npm i workbox-webpack-plugin -D

配置

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

module.exports = {
  mode: 'production',
  entry: './src/app.js',
  plugins: [
    new HtmlWebpackPlugin(),
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true
    })
  ],

浏览器注册

入口文件 app.js

if ('serviceWorker' in navigator) { //浏览器是否支持
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(registration => {
        console.log("SW 注册成功")
        console.log(registration)
      })
      .catch(registrationError => {
        console.log("SW 注册失败", registrationError)
      })
  })
}

shimming 全局变量

webpack配置

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  plugins:[
    new HtmlWebpackPlugin(),
    new webpack.ProvidePlugin({
      _: 'lodash'
    })
  ]
}

使用 index.js

// import _ from 'lodash' //无需引入

console.log(_.join(['hello', 'webpack'], ' '))

细颗粒度 shimming

this问题 imports-loader

安装

npm i imports-loader -D

配置webpack

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  plugins:[
    new HtmlWebpackPlugin(),
    new webpack.ProvidePlugin({
      _: 'lodash'
    })
  ],
  module: {
    rules: [
      {
        test: require.resolve('./src/index.js'),
        use: 'imports-loader?wrapper=window' //让包里的this指向window
      }
    ]
  }
}

全局exports

插件 exports-loader

npm i exports-loader -D

使用 webpack配置

module: {
    rules: [
      {
        test: require.resolve('./src/index.js'),
        use: 'imports-loader?wrapper=window'
      },
      {
        test: require.resolve('./src/global.js'),
        use: 'exports-loader?type=commonjs&exports=file,multiple|helpers.parse|parse' //相当于暴露parse:helper.parse
      }
    ]
  }

polyfills 垫片

简单原理

不能这样引入

安装 @babel/polyfill

npm i @babel/polyfill -D
import '@babel/polyfill' //垫片  这样导入 X

console.log(Array.from([1, 2, 3], x => x + x))

进一步优化

安装babel环境

npm i babel-loader @babel/core @babel/preset-env -D

配置webpack

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  targets: [
                    'last 1 version', //浏览器最新的一个版本
                    '> 1%' //代码使用超过1%
                  ],
                  useBuiltIns: 'usage',
                  corejs: 3
                }
              ]
            ]
          }
        }
      }
    ]
  }

}

额外安装

npm install --save core-js@3

library

打包配置为不同模块

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  experiments: {
    outputModule:true // module时候开启此配置
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'mylib.js',
    library: {
      // name: 'mylib', // module时候取消此配置
      type: 'module'  // window/commonjs/module
    }
  }
}

打包为通用模块

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  // experiments: {
  //   outputModule:true // module时候开启此配置
  // },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'mylib.js',
    library: {
      // name: 'mylib', // module时候取消此配置
      type: 'umd'  // window/commonjs/module/umd
    },
    globalObject: 'globalThis' //全局this代替self
  }
}

构建小轮子

配置

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js',
    library: {
      name: 'webpackNumbers',
      type: 'umd'
    },
    globalObject: 'globalThis'
  },
  externals: { //优化依赖
    lodash: {
      commonjs: 'lodash',
      commonjs2: 'lodash',
      amd: 'lodash',
      root: '_'
    }
  }

}

发布为 npm-package

执行

npm config get registry

确保为

"https://registry.npmjs.org/"

如果不是 切换 npm set registry "https://registry.npmjs.org/"

npm adduser 添加用户

npm publish 发布

模块联邦 多项目共享模块

使用webpack 的 ModuleFederationPlugin

先准备好两个模块

模块nav

组件js Header.js

const Header = () =>{
  const header = document.createElement('h1')
  header.textContent = '公共头部内容'
  return header
}

export default Header

webpack配置项

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' //模块路径
      },
      shared: {} //共享包
    })
  ]

}

模块home引入 nav

webpack配置项

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: { //引入的模块
        nav: 'nav@http://localhost:3003/remoteEntry.js' //网络位置
      },
      exposes: {}, //导出的模块
      shared: {} //共享包
    })
  ]
}

使用nav下的Header

异步加载

import HomeList from "./HomeList";

import('nav/Header').then((Header)=>{
  const body = document.createElement('div')
  body.appendChild(Header.default())
  document.body.appendChild(body)
  document.body.innerHTML += HomeList(5)
})


模块 search 引入两个资源

暴露 home的homeList组件

new ModuleFederationPlugin({
      name: 'home',
      filename: 'remoteEntry.js',
      remotes: {
        nav: 'nav@http://localhost:3003/remoteEntry.js'
      },
      exposes: {
        './HomeList': './src/HomeList.js'
      },
      shared: {}
    })

在webpack配置项引入

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: 'search',
      filename: 'remoteEntry.js',
      remotes: {
        nav: 'nav@http://localhost:3003/remoteEntry.js',
        home: 'home@http://localhost:3001/remoteEntry.js'
      }
    })
  ]
}

在 search 中引入 index.js

Promise.all([import('nav/Header'),import('home/HomeList')])
  .then(([
    {
      default: Header
    },
    {
      default: HomeList
    }
  ]) => {
    document.body.appendChild(Header())
    document.body.innerHTML += HomeList(3)
  })

Promise.all() 可执行多个异步

优化

使用最新版本

webpack 以及 nodejs最新版本

内置优化

将loader应用于最少数量的必要模块

解析必要的 提高打包速度

{
  test: /\.js$/,
  include: 'xxxxxx',
  loader: 'xxx'
}

能不用loader和plugin就不用 引导

解析

减少 resolve,modules,resolve.extensions,resolve.mainFiles,resolve.descriptionFiles中的条目数量 来减少系统文件调用次数

如果 不使用 symlinks 设置resolve.symlinks: false

如果自定义resolve plugin规则 并且没有指定 context,可以设置resolve.cacheWithContext:false

小即快

使用更少或者更小的library

在多页面应用使用splitChunksPlugin 并且开启async

移除未引用代码

只编译当前正在开发的代码

持久化缓存

在webpack配置中使用cache选项 使用package.json中的 "postinstall" 清除缓存目录

将cache类型设置为内存或者文件系统 memory 选项很简单 它告诉webpack在内存中存储缓存

cache: { type: 'memory' }

自定义plugin/loader

对它们概要分析 以免在此处引入性能问题

权衡progress plugin的利弊

通用构建优化 dll

把包生成dll

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

module.exports = {
  mode: 'production',
  entry: {
    jquery: ['jquery']
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dll'),
    library: '[name]_[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]_[hash]',
      path: path.resolve(__dirname, 'dll/manifest.json')
    })
  ]
}

引入

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

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  plugins: [
    new HtmlWebpackPlugin(),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/manifest.json')
    })
  ]
}

此时并不能使用

额外配置

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

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  plugins: [
    new HtmlWebpackPlugin(),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll/manifest.json')
    })
    ,
    new AddAssetHtmlPlugin({
      filePath: path.resolve(__dirname, './dll/jquery.js'),
      publicPath: './'
    })
  ]
}

worker pool

注意 多个loader 从下到上运行

使用 thread-loader

用于非常耗时的loader

因为worker也会消耗资源

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',

  module: {
    rules:[
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options:{
              presets: ['@babel/preset-env']
            }
          },
          {
            loader: 'thread-loader',
            options: {
              workers: 2
            }
          }
        ]
      }
    ]
  }


}

开发环境提升构建性能

使用webpack的 watch mode

监听过多导致的cpu负载

可用watchOptions.poll来增加轮询的时间间隔

在内存中编译

webpack-dev-server

webpack-hot-middleware

webpack-dev-middleware

stats.toJson加速

devtool

eval性能最好 但无法转译

cheap-source-map 稍差的map 但性能不错

eval-source-map 增量编译

多数情况为 eval-cheap-module-source-map

避免使用生产环境的工具

比如

TerserPlugin 压缩和混淆

[fullhash]/[chunkhasn]/[contenthash]

AggressiveSplittingPlugin

AggressiveMergingPlugin

ModuleConcatenationPlugin

最小化 entry chunk

optimization: { runtimeChunk: true }

避免额外优化步骤

optimization: { 
  removeAvailableModules: false,
  removeEmptyChunks: false,
  splitChunks: false
}

输出结果不要带路径信息

output: {
  pathinfo: false
}

nodejs版本

v8.9.10-v9.11.1存在性能回退

ts-loader

use: [
  {
    loader: 'ts-loader',
     options: {
      transpileOnly: true
    }
  }
]

生产环境提升构建性能

不启用 SourceMap

点赞
收藏
评论区
推荐文章
落落落洛克 落落落洛克
3年前
写C端,如何优雅的处理多个弹框的显示?(附带源码)
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
性能优化之防抖和节流
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
React系列-自定义Hooks很简单(下)
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
Redux系列之分析中间件原理(附经验分享)
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
React系列-轻松学会Hooks(中)
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
JavaScript进阶之实现拖拽(上)
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
JavaScript进阶之new的实现
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
落落落洛克 落落落洛克
3年前
React系列之高阶组件
我的前端学习笔记📒最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读我的前端学习笔记📒(https://www.yuque.com/wanggangfeng
小嫌 小嫌
2年前
大佬的搬运工
JS大佬学习笔记很有用niubi的博客各种代码的在线学习教程,是一个很好用的学习代码网站这位大佬对js进行了非常牛逼的总结,其中包括了面试经验,专题,深入,ES6,很强阿里巴巴前端开发学习路线现代JavaScript教程浙江大学师姐前端总结,超强!项目实战react实战项目合集前端线上学习编译器
Stella981 Stella981
2年前
Linux 学习笔记 (四)Ubuntu14.04 解决上网问题安装无线网卡驱动
Linux学习笔记(四)Ubuntu14.04解决上网问题安装无线网卡驱动参考文章:(1)Linux学习笔记(四)Ubuntu14.04解决上网问题安装无线网卡驱动(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.codeprj.com%2Fblog%