首页 > 其他分享 >Webpack解析与讲解

Webpack解析与讲解

时间:2023-02-03 14:25:09浏览次数:65  
标签:依赖 const babel require Webpack 模块 讲解 dependecies 解析

一、什么是Webpack?

  一个基于node.js的前端模块化/预处理/扁平化处理器。

二、为什么要使用Webpack?

  1.  解决业务代码中的各种依赖,模块加载,静态文件引入问题(重复依赖/强依赖,阻塞加载,资源整合)
  2.  使浏览器支持众多样式预处理器(sass, less, stylus)
  3.  使浏览器支持众多第三方框架与工具(react/vue/angluar)
  4.  使浏览器支持ECMA5以上的特性和语法

三、Webpack在打包时都做了些什么?

  1. 生成一个包含入口出口路径模块的compiler类
  2. 获取抽象语法树(AST),建立模块之间关系(@babel/parser)
  3. 找出所有依赖模块(@babel/traverse)
  4. AST 转换为 code(@babel/core 和 @babel/preset-env)
  5. 递归解析所有依赖项,生成依赖关系图(mainfest.json)
  6. 重写 require 函数,输出 bundle(即浏览器能够识别的模块)
const fs = require('fs')
const path = require('path')
const options = require('./webpack.config')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const { transformFromAst } = require('@babel/core')

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  },
  getDependecies: (ast, filename) => {
    const dependecies = {}
    // 遍历所有的 import 模块,存入dependecies
    traverse(ast, {
      // 类型为 ImportDeclaration 的 AST 节点 (即为import 语句)
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename)
        // 保存依赖模块路径,之后生成依赖关系图需要用到
        const filepath = './' + path.join(dirname, node.source.value)
        dependecies[node.source.value] = filepath
      }
    })
    return dependecies
  },
  getCode: ast => {
    // AST转换为code
    const { code } = transformFromAst(ast, null, {
      presets: ['@babel/preset-env']
    })
    return code
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    // 解析入口文件
    const info = this.build(this.entry)
    this.modules.push(info)
    this.modules.forEach(({ dependecies }) => {
      // 判断有依赖对象,递归解析所有依赖项
      if (dependecies) {
        for (const dependency in dependecies) {
          this.modules.push(this.build(dependecies[dependency]))
        }
      }
    })
    // 生成依赖关系图
    const dependencyGraph = this.modules.reduce(
      (graph, item) => ({
        ...graph,
        // 使用文件路径作为每个模块的唯一标识符,保存对应模块的依赖对象和文件内容
        [item.filename]: {
          dependecies: item.dependecies,
          code: item.code
        }
      }),
      {}
    )
  }
  build(filename) {
    const { getAst, getDependecies, getCode } = Parser
    const ast = getAst(filename)
    const dependecies = getDependecies(ast, filename)
    const code = getCode(ast)
    return {
      // 文件路径,可以作为每个模块的唯一标识符
      filename,
      // 依赖对象,保存着依赖模块路径
      dependecies,
      // 文件内容
      code
    }
  }
  // 重写 require函数,输出bundle
  generate() {}
}

new Compiler(options).run()

四、主要涉及知识点:

  1. require/import
  2. AMD/CMD
  3. babel与loader

- require与import

  1. require是一个同步动态加载,导出的是当前整个模块(一次导出多次使用)
 const fs = require('fs') // 其中require的路径是支持模版语法的
 console.log(JSON.stringify(fs.readFileSync)
  1. import是一个同步静态加载,导出的是模块引用(即实现部分导出)
import { addSum } from './path'
addSum()
  webpack最终打出的来的包 还是通过babel降维得到的通过amd/cmd规范组合的require包。

- AMD与CMD(异步加载)

  1. AMD(Async Module Definition) 异步模块定义(require.js)
  define(['./a', './b'], function([a,b])) {
    a.doSomething()
    b.doSomething()
  }

  依赖前置、在定义模块的时候就要声明其依赖的模块

  1. CMD(Common Module Definition) 通用模块定义(sea.js)
define(function(require, exports, module) {   
    var a = require('./a')   
    a.doSomething()   
    var b = require('./b')
    b.doSomething()  
})

就近依赖、只有在用到某个模块的时候再去加载

- babel(Babel 是一个 JavaScript 编译器)

由于浏览器的支持速度远远慢于语言的更新速度。所以我们需要一个强大的能够向下兼容的编译器来帮助浏览器识别我们使用的这些新特性。包括:

  1. 语法转换
  2. 通过 Polyfill 方式在目标环境中添加缺失的特性
  3. 源码转换 (codemods)

eg:

 // Babel 输入: ES2015 箭头函数
  [1, 2, 3].map((n) => n + 1);

  // Babel 输出: ES5 语法实现的同等功能
  [1, 2, 3].map(function(n) {
    return n + 1;
  });

我们现在使用到的很多特性/预设/插件/配置/工具等 都是在有babel这个生态中维护(具体可以参考官网 https://www.babeljs.cn/docs/options)

五、要优化Webpack可以怎么做?

分析 :

BundleAnalyzerPlugin

Speed-measure-webpack-plugin

  1. 优化加载静态资源的大小

    (1) 将资源上传至服务器

    (2) 开启gzip

    (3) 压缩静态资源(图片剔除sourcemap, 代码内容格式化)

    (4) 剔除重复的静态资源

  2. 优化加载(同步/异步)依赖模块的多少

    (1) 合理划分同步加载/异步加载模块(包括路由,依赖,以及第三方库等)

    (2) 尽量使用按需加载,减少依赖重复引用

    (3) 剔除不必要的第三方依赖

    (4) 配置跳过一些大的第三方依赖babel-loader

  3. 添加缓存(manfest.json / babel-loader)

    推荐hardSource(webpack 5.0) 与 webpack(4.0) babel-cache

  4. 启用并行构建(thread-loader)
   (1)注意构建时间:(改进前)

  (2)注意构建时间:(改进后)

 

标签:依赖,const,babel,require,Webpack,模块,讲解,dependecies,解析
From: https://www.cnblogs.com/shyhuahua/p/17089032.html

相关文章

  • webpack核心用法,为什么要使用webpack
    一:为什么使用webpack1.代码转换、文件优化、代码分割、模块合并、自动刷新、等等 2.webpack上手<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF......
  • 网络隔离后的数据传输怎么解决?深度解析4种主流方案
    网络隔离对于很多企业来说并不陌生,出于数据安全的考虑,为了隔离有害的网络和可能的网络攻击,越来越多的企业在内部进行了网络隔离。隔离的形态和方式有多种,总体上主要以物理......
  • 手撕fft系列之频移fftshift源码解析
    壹:fft在数字信号处理领域是一个神一样的存在。要好好熟悉一下。这里给出频移的算法源码解析。所谓的频移,就是把数字信号的频频顺序打乱,移动一些。这个在防止啸叫和......
  • django之drf(部分讲解)
    序列化类常用字段和字段参数drf在Django字段类型的基础上派生了自己的字段类型以及字段参数序列化器的字段类型用于处理原始值和内部数据类型直接的转换还可以用于验证......
  • JAXP、DOM4J、Jsoup、JsoupXPath等常用XML解析器的使用
    (JAXP、DOM4J、Jsoup、JsoupXPath等常用XML解析器的使用)XML概述XML(ExtensibleMarkupLanguage),可扩展标记语言。XML具有标签自定义,语法严格,适用于存储数据与传输数据......
  • 计算机网络-DNS原理和解析过程
    1、DNS系统的简介:DNS是一套从域名到IP的映射系统。TCP/IP中使用IP地址和端口号来确定网络上的一台主机的一个程序,但是IP地址不方便记忆。于是人们发明了一种叫主机名的东西......
  • 货代、海运操作、船务操作的区别 箱讯科技解析
    大型的货代公司操作流程会细分,每个操作都有专人,小货代公司一个人打包以上业务。某些大型的生产厂家也会有海运和船务操作的。货代是货物代理(freightforwardingagent)的简称......
  • Webpack chunk All In One
    WebpackchunkAllInOneWebpack分包打包优化/性能优化dynamicimportscodesplittingcode-splittinghttps://webpack.js.org/guides/code-splitting/https:/......
  • 实战还原--从大黄蜂样本到域控管理员技术解析
    0前言实战案例还原《BumbleBeeRoastsItsWayToDomainAdmin》一文详细的描述了一次渗透案例,但其文章组织架构建立在ATT&CK框架上,而不是按照时间线逻辑来组织,因此对于......
  • lstm内部讲解
    LSTM的内部结构遗忘门输入门细胞状态更新分析输出门参考:https://blog.csdn.net/qq_43894221/article/details/126031830https://blog.csdn.net/weixin_5507364......