bundle
, 什么是 chunk
,什么是module
?module
module是我们经常所说的模块,不管是esModule(import/export或export default)、CommonJs(require/module.exports)、AMD(依赖前置require([‘Ma’,‘Mb’],(a,b)=>_/define({key:value}))都属于module
chunks
chunks是webpack依据module间的引用关系通过代码分割生成的不同chunk文件,同时wenpack也可对chunk文件做些一些操作(如加chunkname)
bundle
bundle是webpack最终经过编译输出output的文件集合,他可以包含多个经过加载和编译后的chunk文件,由于bundle是经过加载和编译的最终源文件,所以直接可以在浏览器运行
webpack实现热更新后,每次更新都会将我们的业务代码和第三方库的代码同时打包更新,降低构建效率,所以需要使用webpack的optimization.splitChunks分离第三方库和业务代码,公共模块直接缓存就不要每次更新都消耗资源
hash 是跟整个项目构建有关,只要项目的文件内容发生变化,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值,所以一旦修改任何一个文件,整个项目的文件缓存都将失效
chunkhash 为避免整个项目的文件因为hash不断变化而导致缓存失效,需要chunkhash,chunkhash根据模块之间引入关系生成不同的chunk文件的同时生成对应的hash值,而不再是所有文件共用同一个hash值 如果需要对chunkhash做进一步优化就需要使用上述所说的optimization.splitChunks或者dllPlugin,可以将公共库以及业务代码抽离而直接缓存公共库,只要公共库只要不发生版本迭代,那么公共库的chunkhash就一直不会变。
contenthash contenthash又是在chunkhash的进一步优化,webpack在根据模块引入关系生成对应的chunk文件,模块可能引入index.css以及index.js,那么当index.js变化而index.css没有变化,则项目更新时inedx.css也会被迫重新加载,导致资源损耗 + 优化方法: 我们可以使用extract-text-webpackplugin(webpack4)里的contenthash值,保证引入css文件所在的模块只要css文件内容不变,就不会重复构建css + 配置方法
var extractTextPlugin = require('extract-text-webpack-plugin') plugins:[ new extractTextPlugin('../css/bundle.[name].[contenthash].css') ]
补充:webpack5已经使用mini-css-extract-plugin代替extractTextPlugin
脚手架的概念和作用:就是拥有完整的开发环境,帮助我们快速的生成一套既定的项目架构、文件、配置。
使用者只需要专注自己的业务代码即可,不需要使用者单独配置
脚手架的构成:
常见的脚手架的开发环境主要分为三种模式:生产模式,开发模式,测试模式。
以及需要配置完整的路由系统(vue-router,react-router-dom),和状态管理系统(vuex,redux)才能保证开发环境的完整性
常见的脚手架:Vue-cli,Creat-React-app,umi-app
万物皆模块:在webpacck的世界中,其他任何资源都可以当做模块的方式引入 代码分割:webapp 的优化关键在于代码体积,当应用体积增大,实现代码的按需加载是刚需,这也是 webpack 出现的根本原因
可定制化:任何一个工具都不可能解决所有问题,提供解决方案才是最可行的,webpack基于可定制化的理念构建,通过插件系统,配置文件,可实现大型项目的定制需求
loader是一个转换器
常用Loader
// 示例
use: [
{
loader: 'url-loader',//等价写法use:'url-loader'?limit=1024
options: {
limit: 8192,
}
},
]
常用Plugin
1、为html文件动态引入外部资源给script、link添加compile(编译)后的hash,防止引用缓文件问题
2、可以生成创建html入口文件,比如单页面可以生成一个html文件入口,多页面生成多个html
首先热更新所更新的内容是基于hash值发生改变的文件
更新的原理方法是webpack-dev-server启动本地服务,源码在webpack-dev-server的package.json中的bin命令,可以找到命令的入口文件bin/webpack-dev-server.js
一、webpack启动后,完成webpack所有编译工作,以及监听本地文件变化
二、使用express框架启动本地服务让浏览器可以请求本地的静态资源。
三、本地服务启动后,再启动websocket服务,通过websocket,可以建立本地服务和浏览器的双向通信,这样就可以实现本地文件变化,立马告知浏览器可以更新了
// node_modules/webpack-dev-server/bin/webpack-dev-server.js
// 生成webpack编译主引擎 compiler
let compiler = webpack(config);
// 启动本地服务
let server = new Server(compiler, options, log);
server.listen(options.port, options.host, (err) => {
if (err) {throw err};
});
// node_modules/webpack-dev-server/lib/Server.js
class Server {
constructor() {
this.setupApp();
this.createServer();
}
setupApp() {
// 依赖了express
this.app = new express();
}
createServer() {
this.listeningApp = http.createServer(this.app);
}
listen(port, hostname, fn) {
return this.listeningApp.listen(port, hostname, (err) => {
// 启动express服务后,启动websocket服务
this.createSocketServer();
}
}
}
不要让loader做太多事情,以babel-loader为例
最常见的优化方式是,用include或exclude来帮助我们避免不必要的转译,除此之外,如果我们开启缓存转译结果缓存至文件系统,则至少可以提升两倍工作效率
use:{
exclude:/(node_module|bower_components)/,
loader:'babel-loader?cacheDirectory=true'
}
不要放过第三方库,以node_modules为代表,庞大又不可或缺。推荐使用DllPlugin
将loader由单进程转为多进程构建
Happypack–将loader由单进程转为多进程,进程是程序运行的数据集合,是系统资源分配基本单位,一般情况下单核cpu只有一个单进程,多核cpu在node的cpu利用率不足的情况下才会由单进程转为多进程。而Happypack帮我们做了这个事儿。多核并发,最大限度使用多核cpu的作用。大大提升效
可视化工具的使用,找出导致文件体积过大的原因
推荐使用webpack-bundule-analyzer,配置方法和普通的 plugin 无异,它会以矩形树图的形式将包内各个模块的大小和依赖关系呈现出来
代码分割的本质: 是能够把代码分离到不同的bundle中,避免出现大体积的代码包,然后可以按需加载或并行加载这些文件 + 代码分离的意义: 代码分离可以获取更小的bundle,以及控制资源加载优先级,合理使用可以极大的减少加载时间 + 代码分割的实现方式有三种: 入口起点:使用entry手动分离代码(不建议)
防止重复加载:使用optimization.splitChunks配置选项,可以将第三方公共模块和业务代码直接分离 动态引入:使用import()方法来分离代码,原理是当 Webpack 解析到该语法时,会自动进行代码分割,分割出不同的chunks
> 语法:使用的时候再去下载对应的文件,返回一个Promise,当Promise成功后再去执行回调,(动态引入的另一种方式是require.ensure()) import("./math").then(math => { console.log(math.add(16, 26)); });
//所有可能匹配此模式的文件都会自动进行代码拆分。 const loadFile = file => import (` ./ $ { file } ` )
import动态语法实现异步加载的代码演示, js function getComponent(){ return import(./loadash).then(_=>{ const element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; }) } getComponent().then(component=>{ document.body.appendChild(component); })
作用:tree-shaking可以实现删除项目中未被引用的代码 原理:
//test.js
export const a =1;
export const b = 2;
// main.js
import {a} from './test.js'
对于以上情况,test文件中的变量b如果没有在项目中使用的话,就不会被打包到文件中 使用: 在webpack4中,开启生产环境就会自动开启这个优化功能,也可以手动的引入ModuleConcatenationPlugin的支持
组件化
就是基础库或者基础组件,意思是把代码重复的部分提炼出一个个组件供给功能使用
模块化
就是业务框架或者业务模块,也可以理解为框架,意思是把功能进行划分,将同一类型的代码整合在一起,所以模块的功能相对复杂,都属于同一个业务。
区别:
使用:组件的使用能在不同项目(模块)重复应用的代码,而模块按照项目功能需求划分成不同类型的业务框架 目的:组件是复用,解耦,模块是为了隔离、封装 依赖:组件之间低依赖,比较独立,模块之间的依赖可通过路由进行耦合 架构定位:组件位于架构底层,被其它层所依赖,模块位于架构业务层