一、什么是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)注意构建时间:(改进后)

Webpack解析与讲解的更多相关文章

  1. webpack详细配置讲解

    //常见的Webpack配置文件var webpack = require('webpack');var HtmlWebpackPlugin = require('html-webpack-plugi ...

  2. webpack解析(1)

    webpack是为现代js程序准备的静态模块打包工具 一:关于对webpack的理解 可以将其认为是一个电脑主板,由于使用js作为源码,因而其可以默认编译js代码(别种类型的文件可以依靠loaders ...

  3. 如何使用webpack打包前端项目

    webpack概述 随着前端体积越来越大,功能越来越丰富,这时候就需要将前端工程化,而 webpack就是用于将前端各种文件打包起来. 一个简单的webpack应该包含以下几个概念 · 入口起点 · ...

  4. webpack详解

    webpack是现代前端开发中最火的模块打包工具,只需要通过简单的配置,便可以完成模块的加载和打包.那它是怎么做到通过对一些插件的配置,便可以轻松实现对代码的构建呢? webpack的配置 const ...

  5. vue - webpack、babel

    一.webpack 在这里我仅仅的是对webpack做个讲解,webpack这个工具非常强大,解决了我们前端很繁琐的一些工具流程繁琐的事情.如果感兴趣的同学,建议还是看官网吧. 中文链接地址:http ...

  6. webpack4.x最详细入门讲解

    前言 本文主要从webpack4.x入手,会对平时常用的Webpack配置一一讲解,各个功能点都有对应的详细例子,所以本文也比较长,但如果你能动手跟着本文中的例子完整写一次,相信你会觉得Webpack ...

  7. android基础(五)网络数据解析方法

    在网络上传输数据时最常用的方法有两种:XML和JSON,下面就对这两种类型的数据解析进行讲解. 一.XML数据解析 在Android中,常见的XML解析器分别为SAX解析器.DOM解析器和PULL解析 ...

  8. PULL解析XML的运行机制详解

    PULL解析简单易上手,基本上看一遍,基本上就会解析啦,但总是感觉对PULL解析的运行机制不是很了解,就总结了以下事件驱动到底是怎么执行的.. PULL: Android内置了PULL解析器.PULL ...

  9. iOS开发之JSON格式数据的生成与解析

    本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...

  10. 前后端分离之vue2.0+webpack2 实战项目 -- webpack介绍

    webpack的一点介绍 Webpack 把任何一个文件都看成一个模块,模块间可以互相依赖(require or import),webpack 的功能是把相互依赖的文件打包在一起.webpack 本 ...

随机推荐

  1. vue2源码学习2vuex&vue-router

    1.vue插件编写 插件可以实现对象vue的拓展,比如新增全局属性/方法,添加实例方法,使用mixin混入其他配置项等等.编写插件必须要实现 install 方法,当调用Vue.use()使用插件时, ...

  2. 用Bootstrap设计后端页面模板

    <!doctype html><html lang="zh-CN"> <head> <meta charset="utf-8&q ...

  3. cookie、session入门

    一.cookie是由http制定的 二.使用方法 1.原始方法 使用request接受Cookies请求头 使用response发送set-Cookies响应头 2.常用方法 response.add ...

  4. Prettier 与 ESLint 对函数名后空格的处理

    问题 Prettier 格式化 JavaScript 代码之后,默认不会在函数与 () 添加空格,而 ESLint 默认情况下则要求函数与 () 之间必须有一个空格. 保留空格的方案配置 方案 1 在 ...

  5. python的GIL全局解释器锁

    global interpreter lock -- 全局解释器锁 CPython 解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python bytecode.此机制通过设置对象模型(包 ...

  6. vs输出重定向

    1.右键点击解决工程->项目属性 2.配置属性->生成事件->生成后事件 在命令行中输入:"$(TargetPath)  >$(outdir)\1.txt" ...

  7. k8s_service

    service 功能 主要是提供负载均衡和服务自动发现. pod的ip会随着升降级.销毁的操作改变.客户端不能直接访问pod的ip. service资源被用于在被访问的pod对象中添加一个有着固定IP ...

  8. maven加载本地的jar包

    方式1 ,通过scope = system的方式加载 <dependency> <groupId>com.sun.jna</groupId> <artifac ...

  9. docker镜像原理(二)

    一.docker镜像定义 如果我们想要定义mysql5.7镜像应该怎么做? 获取基础镜像,选择一个发行版平台(unbtu.centos) 在centos镜像中安装mysql5.7软件 导出镜像,可以命 ...

  10. go标准库之fmt

    go标准库之fmt fmt库 Print系列 1. Print 不换行 2. Println 换行 3. Printf 不换行,可以使用格式化占位符 格式化占位符 占位符 说明 通用 --- %v 值 ...