PS:根据B站学习视频 :【2020新课程】Webpack从原理到实战完整版-深入浅出,简单易学,前端工程师必学经典内容!学习整理,如有错误,欢迎随时指正,互相学习。
重点:
- 理解前端模块化
- 理解 webpack 打包的核心思路
- 理解 webpack 中的 “关键人物”
模块化的特点:
作用域概念:决定了代码中变量、函数、对象等其他资源的可见性。
当我们把 js 逻辑代码按功能分成不同的 js 文件时,在 HTML 中引入,后引入的文件就可以访问前者文件的变量、对象等资源,这样可能会造成命名冲突,值覆盖等不可控的结果。
// a.js 文件 var a = 1; // b.js 文件 var a = 2; // c.js 文件 console.log(a);// 2
所以我们利用作用域的效果,把每个文件中的 js 代码封装到一个对象中,这样我们在需要取值的时候就可以分离开。
// a.js 文件 var moduleA = { a: 1 }; // b.js 文件 var moduleB = { b: 2 }; // c.js 文件 console.log(moduleA.a);// 1
但是当我们需要存储账号密码这种数据时,这样做的话安全性不高,并且容易被其他文件更改,我们并不希望其他文件能访问到我特殊数据,只希望执行我们提供给他的方法。所以我们应该封装到函数中并且返回,这样我们既达到了隐藏特殊数据的效果又达到了功能的复用,并且兼顾了命名冲突产生的可能性。
// a.js 文件 var user = (function() { var username = 'abc'; var password = 123; return { login: function() { // ...逻辑代码 console.log( username + '登录成功'); } } })(); // b.js 文件 user.login();// adc登录成功
但是声明变量是不能通过 delete 操作符删除(还可能更占用内存?),采用更规范的写法:
// a.js 文件 (function(window) { var username = 'abc'; var password = 123; function login() { // ...逻辑代码 console.log( username + '登录成功'); } window.moduleA = {login};// 挂载到 window 对象上 })(window);// 传入 window // b.js 文件 module.login();// adc登录成功
Asynchronous Module Defineition (异步模块定义)
优点:
// 求和模块的定义 // define(当前函数ID,当前模块依赖,函数/对象) 函数:利用函数的返回值,导出模块的接口 对象:对象本身就是模块导出值 define('getSum',['math'],function(math) { return function(a,b) { console.log('sum:'+ math.sum(a,b)); } });
最初为了解决服务端的模块化标准,后 Node.js 采用并实现其规范。
在 CommonJS 中,每个文件就是一个模块,并且拥有他自己的作用域和上下文,模块的依赖通过 require 函数引入,通过 exports 将其导出。
同 AMD 一样,强调依赖的显示,方便维护复杂模块时,不用操心各个模块的引入顺序。
// 引入 const math = require('./math'); // 导出 exports.getNum = function(a,b) { return a + b; };
// import 引入 import math from './math'; // export 导出 export function sum(a,b) { return a + b; }
- 理解包管理器
- 熟悉 npm 核心特性
- 理解 npm "仓库"与"依赖"的概念
- 理解 npm “语义化版本”
- 掌握使用 npm 自定义工程脚本的方法
是一个遵循 npm 特定包规范的站点,提供 API 进行下载、上传、获取包信息、管理用户账号等操作。
在开发/生产中所需要用到的外部资源被称为依赖。
优势:方便 npm 包的发布者很便捷的把更新的小版本推送到使用者手里。
主要从三个方面入手:
const TerserPlugin = require("Terser-webpack-plugin"); optimization:{ minimizer: [ new TerserPlugin({ // 加快构建速度 parallel: true, // 开启多线程处理,加快构建速度 terserOptions: { compress: { // 剔除发布时没有用的代码的配置 unused:true, // 剔除 debugger drop_Debugger: true, // 剔除 console drop_console: true, dead_code: true } } }) ] },
通过使用 webpack-bundle-analyzer 可以在打包完成后看到项目各模块的大小,以便于按需优化。
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); plugins: [ new BundleAnalyzerPlugin() ],
相关文章:
使用 happypack 提升 Webpack 项目构建速度
happy pack 原理解析
Happypack 只是作用在 loader 上,使用多个进程同时对文件进行编译。
npm install happypack --save-dev
webpack.config.js
const os = require('os') const HappyPack = require('happypack'); // 根据 CPU 的数量创建线程池 const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); plugins: [ new HappyPack({ id: 'jsx', threadPool: happyThreadPool, // 使用时应注意该 loader 是否支持 happyPack loaders: ['babel-loader'] }) ],
thread-loader官方指南
使用时,需要将此 loader 放置在其他所有 loader 之前。会将该 loader 之后的 loader 放在一个独立的 worker 池中运行,达到多线程构建的目的。
npm install --save-dev thread-loader
webpack.config.js
module.exports = { module: { rules: [ { test: /\.js$/, include: path.resolve('src'), use: [ "thread-loader", // 耗时的 loader (例如 babel-loader) ], }, ], }, };
个人的一点小总结,不足以作为参考依据。
- 在测试时,使用 happypack、thread-loader 对项目构建速度提升不明显,甚至可能减缓构建速度,所以在小型项目中没有必要使用。
- 都是通过创建线程池,本质上是通过多进程实现打包加速。进程、线程和协程之间的区别和联系
DCE 的一种新的实现方式。
本质:消除无用的 js 代码。
理解:通过摇晃一个树,摒弃无用的枯叶,只留下茂盛的树叶和果实。
作用:例如 tool.js 中封装了很多公共方法,其中 A 方法只引入没调用,那么在 development 环境打包结果中你能看到 A 方法的打包结果,但在 production 环境打包结果中就移除了 A 方法。
PS:如有错误,请多多指正!