webpack学习笔记

2021/4/11 18:26:16

本文主要是介绍webpack学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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登录成功

从立即执行函数为起点的模块化实现方案

AMD

Asynchronous Module Defineition (异步模块定义)

优点:

  • 显示出当前模块所依赖的其他模块有哪些。
  • 不用绑定到全局对象上,更近一步增加模块安全性,不担心在其他地方被篡改。
// 求和模块的定义
// define(当前函数ID,当前模块依赖,函数/对象)  函数:利用函数的返回值,导出模块的接口 对象:对象本身就是模块导出值
define('getSum',['math'],function(math) {
    return function(a,b) {
        console.log('sum:'+ math.sum(a,b));
    }
});

CommonJS

最初为了解决服务端的模块化标准,后 Node.js 采用并实现其规范。

在 CommonJS 中,每个文件就是一个模块,并且拥有他自己的作用域和上下文,模块的依赖通过 require 函数引入,通过 exports 将其导出。

同 AMD 一样,强调依赖的显示,方便维护复杂模块时,不用操心各个模块的引入顺序。

// 引入
const math = require('./math');
// 导出
exports.getNum = function(a,b) {
    return a + b;
};

ES6 Module

// import 引入
import math from './math';
// export 导出
export function sum(a,b) {
	return a + b;    
}

npm

  • 理解包管理器
  • 熟悉 npm 核心特性
  • 理解 npm "仓库"与"依赖"的概念
  • 理解 npm “语义化版本”
  • 掌握使用 npm 自定义工程脚本的方法

package.json 属性说明

  • name - 包名
  • version - 包的版本号。
  • description - 包的描述。
  • homepage - 包的官网URL。
  • author - 包的作者,它的值是你在 https://npmjs.org 网站的有效账户名,遵循“账户名<邮件>”的规则,例如:zhangsan zhangsan@163.com
  • contributors - 包的其他贡献者。
  • dependencies / devDependencies - 生产 / 开发 环境依赖包列表。它们将会被安装在 node_module 目录下。
  • repository - 包代码的Repo信息,包括type和URL,type可以是git或svn,URL则是包的Repo地址。
  • main - main 字段指定了程序的主入口文件,require(‘moduleName’) 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
  • keywords - 关键字
  • script - 自定义命令

“仓库”

是一个遵循 npm 特定包规范的站点,提供 API 进行下载、上传、获取包信息、管理用户账号等操作。

“依赖”

在开发/生产中所需要用到的外部资源被称为依赖。

“语义化版本”

优势:方便 npm 包的发布者很便捷的把更新的小版本推送到使用者手里。

  • ^version:中版本和小版本
  • ~version:小版本
  • version:特定版本

npm install 的过程

  • 寻找包版本信息文件 (package.json),依赖这个文件进行安装
  • 查看 package.json 中的依赖,并检查项目中其他的版本信息文件
  • 如果发现新包,就更新版本信息文件

webpack 的打包过程

  • 从入口文件开始,分析整个应用的依赖树
  • 将每个依赖模块包装起来,放到一个数组中等待调用
  • 实现模块加载的方法,并把他们放到模块执行的环境中,确保模块间可以互相调用
  • 把执行入口文件的逻辑放在一个函数表达式中,并立即执行这个函数

webpack 核心特性

  • 使用 webpack 构建简单的工程
  • 了解 webpack 配置文件
  • 掌握“一切皆模块与loaders”的思想
  • 理解 webpack 中的“关键人物”

webpack 构建工程

  • 掌握 babel 的用法,理解 babel 的原理

webpack 性能调优

主要从三个方面入手:

  • 打包结果优化
  • 构建过程优化
  • Tree - Shaking

TerserPlugin

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

BundleAnalyzerPlugin 打包文件分析工具

通过使用 webpack-bundle-analyzer 可以在打包完成后看到项目各模块的大小,以便于按需优化。

const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
plugins: [
    new BundleAnalyzerPlugin()
],

happyPack

相关文章:

  • 使用 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

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 对项目构建速度提升不明显,甚至可能减缓构建速度,所以在小型项目中没有必要使用。
  • 都是通过创建线程池,本质上是通过多进程实现打包加速。进程、线程和协程之间的区别和联系

tree-shaking

DCE 的一种新的实现方式。

本质:消除无用的 js 代码。

理解:通过摇晃一个树,摒弃无用的枯叶,只留下茂盛的树叶和果实。

作用:例如 tool.js 中封装了很多公共方法,其中 A 方法只引入没调用,那么在 development 环境打包结果中你能看到 A 方法的打包结果,但在 production 环境打包结果中就移除了 A 方法。

PS:如有错误,请多多指正!



这篇关于webpack学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程