ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

webpack学习笔记

2021-04-11 18:04:37  阅读:136  来源: 互联网

标签:npm 文件 笔记 loader 学习 webpack 模块 js


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 只是作用在 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:如有错误,请多多指正!

标签:npm,文件,笔记,loader,学习,webpack,模块,js
来源: https://blog.csdn.net/weixin_49834243/article/details/115600899

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有