资讯专栏INFORMATION COLUMN

webpack 基础与项目优化实践总结

Scorpion / 3208人阅读

摘要:前言本文基于,主要涉及基本概念基本配置和实际项目打包优化。关于概念方面参考官网,常用配置来自于网络资源,在文末有相关参考链接,实践部分基于自己的项目进行优化配置。同一文件中,修改某个影响其他。

前言:本文基于weboack4.x,主要涉及webpack4 基本概念、基本配置和实际项目打包优化。关于概念方面参考官网,常用配置来自于网络资源,在文末有相关参考链接,实践部分基于自己的项目进行优化配置。

webpack 四大概念 entry

定义编译打包入口文件。类型:字符串(单入口)、对象(多入口)

entry: "./src/index.js"
// 等同于
entry: {
    main: "./src/index.js"
}
output

1、filename:
[name]: 对应着entry中对象的key
[id]: 内部的chumk id
[hash]: 每次打包编译的唯一hash,改动会影响整个项目的打包,缓存失效
[chunkhash]:对应着每个入口文件计算而来的hash,唯一,文件之间互不影响
[contenthash]: contenthash = (moduleId + content) 生成的hash。同一文件中,修改某个module影响其他module。例如,js代码中引入css文件,修改js文件造成css文件的hash改变

2、path: 是配置输出文件存放在本地的目录,字符串类型,是绝对路径puclicPath: 对构建出的资源进行异步加载(图片,文件) 时候的路径前缀, 可以看作静态文件托管在cdn
3、chunkFilename: 决定了非入口(non-entry) chunk 文件的名称,如按需加载、异步加载

参考:从零搭建webpack4 之output输出

Module 配置Loader

rules 数组,包含多个处理文件的 loader 配置

条件匹配: 通过test、include、exclude三个配置来命中Loader要应用的规则文件。

应用规则: 对选中后的文件通过use配置项来应用loader,可以应用一个loader或者按照从后往前的顺序应用一组loader。同时还可以分别给loader传入参数。

重置顺序: 一组loader的执行顺序默认是从有道左执行,通过exforce选项可以让其中一个loader的执行顺序放到最前或者是最后。

loader配置属性

test:类型正则、字符串、数组。匹配文件
use:类型字符串、对象、数组【loader字符串或对象】。对选中的文件应用loader。

    对象中包含:loader、options:loader的具体配置参数、enforce: 改变该loader的执行的顺序【pre/post】

include: 指定需要处理的文件。类型:一般为路径、可以是数组类型。
exclude:排除不需要处理的文件。类型:一般为路径、可以是数组类型。
noParse: 排除对没有采用模块化的文件解析和处理,类似:jQuery。 类型:RegExp, [RegExp], function其中一个。
parser:可以更细粒度的配置哪些模块语法【AMD、CommonJS、ES6等】是否需要解析

Plugin

Plugin 是用来扩展Webpack 功能的,通过在构建流程里注入钩子实现,它为Webpack 带
来了很大的灵活性。主要在打包的某个阶段执行该插件,对文件进行处理,类似于钩子函数

tree shaking

触发treeshking条件:
1.需要代码是es module规范的并且使用解构赋值的方式引入,
2.开启optimization.usedExports:true来标记使用和未使用的模块,

使用压缩的插件进行删除未使用代码。

webpack4的mode设置为production,默认开启optimization.usedExports和使用代码压缩

注:
1、tree shaking 不能作用于有副作用side-effect的代码
如果所有代码没有副作用,在package.json 中添加

 sideEffects: false

如果存在副作用代码/模块,

sideEffects: [
".src/some-side-effectful-file.js",
"*.css"
]
"side effect(副作用)" 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。

2、不要意外地将 ES 模块编译成 CommonJS 模块。如果你使用 Babel 的时候,采用了 babel-preset-env 或者 babel-preset-es2015,请检查这些预置的设置。默认情况下,它们会将 ES 的导入和导出转换为 CommonJS 的 require 和 module.exports,可以通过设置.babelrc中 { modules: false } 选项来禁用它

参考:webpack tree shaking 的三个要点

HMR (Hot Module replacement)模块热替换
devServer: {
proxy: {
"/api": {
target: "http://localhost:3000",
pathRewrite: {"^/api" : ""}
},
context: ["/api", "/online"], //匹配多个路径,同时代理到同一个站点
target: "http://localhost:3000"
},
    hot: true,
    hotOnly: true
}
code spiliting

把代码分离到不同的 bundle 中,可以按需加载或并行加载这些文件

实现方式:
1、入口配置:entry 入口使用多个入口文件 =》 存在重复引用的模块
2、抽取公有代码:使用 SplitChunksPlugin 抽取公有代码,取代CommonsChunkplugin

 webpack.config.js 配置:
```

  optimizition: {
    splitChunks: {
        chunks: "all"        
    }
 }
```

3、动态加载 :动态加载一些代码 =》 ECMAScript 提案 的 import() 语法
方式1 + 方式2 需要配合使用,才能达到代码抽离的效果

prefetch && preload

prefetch(预取):将来某些导航下可能需要的资源
preload(预加载):当前导航下可能需要资源

import(/* webpackPrefetch: true */ "LoginModel");

/ webpackPrefetch: true /:把主加载流程加载完毕,在空闲时在加载其他,等再点击其他时,只需要从缓存中读取即可,性能更好。推荐使用,提高代码利用率。把一些交互后才能用到的代码写到异步组件里,通过懒加载的形式,去把这块的代码逻辑加载进来,性能提升,页面访问速度更快。
/ webpackPreload: true /: 和主加载流程一起并行加载。

lazy loading

import() 异步加载加载的模块,开启代码分割后,会被多带带打包在一个文件中
路由懒加载

const Login = () => import("./components/login")

模块异步加载

 import(/* webpackChunkName: "vendor"*/ "./page/vendor.js").then(({default: _}) => {// todo})
公共代码提取

mini-css-extract-plugin 用于提取公共css,取代 webpack 3 的 extract-text-webpack-plugin
注:一般适用于生产环境,在开发环境会导致HMR功能缺失;在开发环境,使用style-loader
使用方式:

const MiniCssExtractPlugin=require("mini-css-extract-plugin")
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin") // 代码压缩
// modules 中
// css,scss,sass,less
{
test:/.(sa|sc|c)ss$/,
use: [
process.env.NODE_ENV === "development" ? "style-loader": MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
optimization: {
minimizer: [new OptimizeCssAssetsPlugin({})]
},


//plugins中
new MiniCssExtractPlugin({
filename: "[name].css"
})
DllPlugin & DllReferencePlugin

防止第三方包多次编译打包。 第一次打包时,把第三方模块多带带打包生成一个文件 vendors.dll.js,之后在打包时就可以直接从 vendors.dll.js 中引入之前打包好的第三方模块
实现过程:
1、编写一个用于生成动态链接库的配置文件
2、运行生成动态链接库和对应的.mainfest.json映射文件
3、在webpack.config.js中使用动态链接库。这样第二次编译打包会从json文件中找相应的模块

webpack.dll.config.js

module.exports = {
    entry: {
        react: ["react"] //react模块打包到一个动态连接库
    },
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "[name].dll.js", //输出动态连接库的文件名称
        library: "_dll_[name]" //全局变量名称
    },
    plugins: [
        new webpack.DllPlugin({
            name: "_dll_[name]", //和output.library中一致,值就是输出的manifest.json中的 name值
            path: path.join(__dirname, "dist", "[name].manifest.json")
        })
    ]
}

webpack.config.js

plugins: [
  new webpack.DllReferencePlugin({
  manifest: require(path.join(__dirname, "dist", "react.manifest.json")),
})
],

提高webpack的构建(打包/build)速度

多入口情况下,使用SplitChunk来提取公共代码

通过externals配置来提取常用库

利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。

使用Happypack 实现多线程加速编译

使用webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度

使用Tree-shaking和Scope Hoisting来剔除多余代码

模式分离

webpack 作为模块化打包工具, 常用来对项目进行打包进行本地调试和发布到线上,所以无论是自己在项目配置使用webpack还是使用开发框架的脚手架进行开发,都需要区分开发和生产环境。在webpack4 的配置项中添加了 mode属性,可以用来区分两者模式。
下面是开发和生产模式下一些默认配置和区别:

development 模式下,默认开启了NamedChunksPlugin 和NamedModulesPlugin方便调试,提供了更完整的错误信息,更快的重新编译的速度。
production 模式下,由于提供了splitChunks和minimize,代码就会自动分割、压缩、优化,同时 webpack 也会自动帮你 Scope hoisting 和 Tree-shaking

优化划分 体积优化 工具 - 打包文件可视化

使用 webpack-bundle-analyzer, 可直观的看出打包后每个模块所占比例和大小
使用方法:

安装
npm i -D webpack-bundle-analyzer

2.在 package.json -> script 中添加启动命令
"analyz": "cross-env NODE_ENV=prodution npm_config_report=true npm run build"

3.在 webpack.pro.conf.js -> plugin 添加以下代码,可以改变启动时的端口等配置
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
new BundleAnalyzerPlugin({analyzerPort: 8089})

关于使用方法详细可参考:webpack实践-webpack-bundle-analyzer使用

具体方案 路由懒加载

import xxxx from "@componets/xxx" => const xxx = () => require("@componets/xxx")

模块化按需加载

对于一些类似antd、element-ui、eCharts等库,可以按需引入,没有必要全局引入,具体方法见官方文档
对于loadash等API依赖工具,结合lodash-webpack-plugin和babel-plugin-lodash,实现按需引入,把需要的API一次性引入,并挂载在全局上

// 从lodash 中统一引入你需要的方法
import _ from "lodash"

export default {
cloneDeep: _.cloneDeep,
debounce: _.debounce,
throttle: _.throttle,
size: _.size,
pick: _.pick,
isEmpty: _.isEmpty
}

// 注入到全局
import _ from "@helper/lodash.js"
Vue.prototype.$_ = _

// vue 组件内运用
this.$_.debounce()
外部模块使用CDN

对于类似Jquery等大而使用较少的库,可以在index.html使用cdn引入;如果顾虑到可能造成外部攻击等问题,可以下载成为本地资源,再引入

参考:webpack 打包优化之体积篇

速度优化 实现方法 缩短路径,减小文件搜索范围

1、缩小文件搜索范围或者指定特定的文件夹位置
2、排除不需要进行处理的文件
......

使用并发压缩插件

不使用默认的 UglifyJs,使用并行压缩工具 webpack-parallel-uglify-plugin
......

具体参考:webpack 打包优化之速度篇

实践 vue 项目

我是在我之前开发一大型项目使用webpack进行项目优化
注:此项目使用的webpack版本为2.x,不是最新版本4.x,由于项目比较复杂,升级带来的潜在问题可能比较多,时间精力有限,暂时未升级
项目技术和库:vue全家桶 + vue-cli + webpack + jQuery + element-UI + eCharts ...
按照上文中的常用配置,就打包速度和体积进行了优化,从而导致页面加载速度得到一定提升
图片上传失败,显示不出来 【手动捂脸】

最后

由于本文参考了许多相关文章,并加以自己的理解和实战,如有不妥之处,请多包涵并指出,谢谢

参考:
webpack实践——webpack-bundle-analyzer 的使用
从基础到实战 手摸手带你掌握新版Webpack4.0详解 教你看文档
webpack 4.0 基础到实战配置github
webpack 官方文档
关于webpack的面试题总结

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104930.html

相关文章

  • 前端每周清单半年盘点之 Angular 篇

    摘要:延伸阅读学习与实践资料索引与前端工程化实践前端每周清单半年盘点之篇前端每周清单半年盘点之与篇前端每周清单半年盘点之篇 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为新闻热点、开发教程、工程实践、深度阅读、开源项目、巅峰人生等栏目。欢迎关注【前端之巅】微信公众号(ID:frontshow),及时获取前端每周清单;本文则是对于半年来发布的前端每周清单...

    LeviDing 评论0 收藏0
  • 前端每周清单第 48 期:Slack Webpack 构建优化,CSS 命名规范用户追踪,Vue.

    摘要:发布是由团队开源的,操作接口库,已成为事实上的浏览器操作标准。本周正式发布,为我们带来了,,支持自定义头部与脚部,支持增强,兼容原生协议等特性变化。新特性介绍日前发布了大版本更新,引入了一系列的新特性与提升,本文即是对这些变化进行深入解读。 showImg(https://segmentfault.com/img/remote/1460000012940044); 前端每周清单专注前端...

    sean 评论0 收藏0
  • React同构直出优化总结

    摘要:同构的关键要素完善的属性及生命周期与客户端的时机是同构的关键。的一致性在前后端渲染相同的,将输出一致的结构。以上便是在同构服务端渲染的提供的基础条件。可以将封装至的中,在服务端上生成随机数并传入到这个中,从而保证随机数在客户端和服务端一致。 原文地址 React 的实践从去年在 PC QQ家校群开始,由于 PC 上的网络及环境都相当好,所以在使用时可谓一帆风顺,偶尔遇到点小磕绊,也能够...

    alaege 评论0 收藏0
  • React 历史项目维护优化实践

    摘要:本文介绍了作者接手维护一个中型历史项目时的一系列改进实践,包括模块结构拆分业务逻辑梳理打包优化等。代码中如菜单名称结构表单字段名等的各种硬编码配置分散在各处。最后,在提升面向开发者的打包体验方面,本次优化中主要实现的是与的解耦。 本文介绍了作者接手维护一个中型 React 历史项目时的一系列改进实践,包括模块结构拆分、业务逻辑梳理、Webpack 打包优化等。 背景 这是一个 PC 的...

    toddmark 评论0 收藏0
  • 前端每周清单半年盘点之 React ReactNative 篇

    摘要:前端每周清单半年盘点之与篇前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。与求同存异近日,宣布将的构建工具由迁移到,引发了很多开发者的讨论。 前端每周清单半年盘点之 React 与 ReactNative 篇 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为...

    Barry_Ng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<