模块化
common.js 的导入导出方法: require \ export 和 module.exports
export 和 module.export
nodejs 内存1.4G -> 2.8G
cjs
ESModule
主要区别: require属于动态类型:加载执行 同步
esmodul是静态类型:引入时并不会真的去执行文件 而是先分析依赖关系 再再实例化 最后执行 异步
import 是promise的语法糖 沙箱机制
外链 软链 link
python php 解释型语言
js 编译型语言
前端三件事:
- 设计:
webpack的设计:
文件加载:
1)从什么地方加载,入口文件,以参数形式写入 './index.js'
2) 文件加载方法名:getFileInfo(file) - file 文件路径 index.js
分析方法名 parseFile(Filecontent) - Filecontent 文件内容
加载完成文件,文件上下文,require,import, 写入dist、bundle.js
3) 收集依赖
npm install @babel/traverse
4)收集完依赖,加载所有⽂件
内部的文件加载情况,依赖关系
根据依赖关系加载文件
- parseModules⽅法:
- 我们⾸先传⼊主模块路径
- 将获得的模块信息放到temp数组⾥。
- 外⾯的循坏遍历temp数组,此时的temp数组只有主模块
- 循环⾥⾯再获得主模块的依赖deps
- 遍历deps,通过调⽤getModuleInfo将获得的依赖模块信息push到 temp数组⾥。`
- 使得引⼊的代码可以被执⾏最终需要处理require和exports
- 注释
- 测试
npm init 初始化项目得到package.json 和 package-lock.json文件npm install 安装依赖
npm install @babel/parser 安装解析器babel
npm install @babel/traverse 收集完依赖,怎么加载所有⽂件
@babel/preset-env es6的代码转成es5的(import es7的语法 浏览器不认识 转成es5)
引⼊的代码可以被执⾏最终需要处理require和exports
babel里的每个stage代表什么内容: 核心原理是什么
能转义和兼容的范围
低阶段兼容范围更广
高阶段能兼容最新的语法
低阶段包含高阶段
use strict: 严格模式作用:避免js灵活性造成的问题
用法:文件开头标识 use strict
不能干的事:严格使用js的语法
- 全局this
- 变量重复定义:为了避免掉js的灵活性造成的问题 避免歧义
- eval函数 string变成函数去执行的情况
webpack 原生加载器能加载哪些文件: js 和 jsonwebpack不具备这些功能 通过插件完成
手写实现webpack
webpack的核心概念
ts
1. sourcemap
2. 文件指纹技术
3. babel 与 AST
4. TreeShaking
5. 优化
- 构建速度
- 提高页面性能
6. 原理
- webpack
- plugin
- loader
7. 核心配置
- entry: 编译入口,webpack编译的起点
- Compiler: 编译管理器, webpack启动后会创建compiler对象,知道结束退出
- compilation: 单次编辑过程的管理器
- dependence: 依赖对象 webpack基于该类型记录模块间依赖关系
- Module: 内部资源都以module形式存在 所有关于资源的操作,转译,合并都是以module为单位进行的
- Chunk:百年已完成准备输出是 webpack会将module按照特定的规则组织称一个个chunk 跟最终输出一一对应
- Loader: 资源内容转换器
- Plugin: webpack构建过程中,会在特定的时机⼴播对应的事件,插件监听这些事件,在特定时间点介⼊编译过程
在代码里debug
vscode里debug
- 执行完 按语句执行 单步调试:进入到语句里去 单步跳出 刷新 暂停
- 代码里写 debugger然后启动
手写实现webpack 理解原理完整代码
ts
// src下创建 add.js⽂件和minus.js⽂件, 在index.js中引⼊,再将index.js⽂件引⼊index.html
// add.js
export default ( a, b ) => {
return a + b
}
// minus.js
export const minus = ( a, b ) => {
return a - b
}
// index.js
import add from './add.js'
import { minus } from './minus.js'
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="./src/index.js" type="module"></script>
</body>
</html>
// 创建bundle.js文件
// 获取主入口文件
// 解决内部文件循环引用的问题 npm install @babel/parser 解析器
// 收集依赖
// 根据收集的依赖关系 加载所有文件
// 执行加载的文件:浏览器处理不了es67的语法 require、import需要被处理
const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')
const getmoduleInfo = (file) => {
// 读取文件
const body = fs.readFileSync(file, 'UTF-8')
const ast = parsesr.parse(body, {
sourceType: 'module' // 表示我们要解析的是ES模块
})
const deps = {}
//
traverse(ast, {
// 处理路径
ImportDeclaration({node}){
const dirname = path.dirname(file)
const abspath = "./" + path.join(dirname, node.source.value)
}
})
// 转成ast树
const { code } = babel.transformFromAst(ast, null,{
presets: ["@babel/preset-env"]
})
const moduleInfo = { file, deps, code}
return moduleInfo
}
// 解析模块
const parseModules = (file) => {
// 入口文件
const entry = getModuleInfo(file)
const temp = [entry]
const depsGraph = {}
for(let i=0;i<temp.length;i++>){
const deps = temp[i].deps
if(deps){
for(const key in deps){
if(deps.hasOwnProperty(key)){
temp.push(getModuleInfo(deps[key]))
}
}
}
}
temp.forEach(moduleInfo => {
depsGraph[moduleInfo.file] = {
deps: moduleInfo.deps,
code: moduleInfo.code,
}
})
}
// 生成最终bundle文件
const bundle = (file) => {
const depswGraph = JSON.stringify(parseModules(file))
return `
(
function(graph){
function require(file) {
function absRequire(relPath){
return require(graph[file].deps[realPath])
}
var exports = {}
(function (require,exports,code){
eval(code)
})(absRequire, exportsgraph[file].code)
return exports
}
require('$file')
}
)($depsGraph)
`
}
const content = bundle('./src/index.js')
// 写入到dist目录下
fs.mkdirSync('./dist')
fs.writeFileSync('./dist/bundle.js',content)
webpack5.0优化
- 增加持久化存储能力,提升构建性能(核心)
- 提升算法能力来改进长期缓存(降低产物缓存资源的失效率)
- 提升treeshaking的能力未降低产物大小和代码生成逻辑
- 提升web平台的兼容性能力
- 清除了内部结构中在webpack4没有重大更新二引入的一些新特性时留下来的一些奇怪的state
- 引入一些重大的变更为未来的一些特性做准备,使得能长期稳定在webpack版本上
如何优化
vite
rollup: 编译工具
esbuilder:go语言
为什么vite在开发时用 esbuild, 生产环境用打包 rollup
- esbuild不支持es5 不会降级
- 不支持render
- 不支持split chunk
可以把一些包放到npm上
CICD: shell 的命令
控制并发请求数量
javascript
// 并发控制: 10条数据 控制请求的数量不大于三条
request(url, maxNum){
return new Promise(resolve,reject=>{
if(urls.length){
resolve([])
return
}
const result= []
let index = 0 // 下一个请求的下标
let count = 0 // 当前请求完成的数量
// 发送请求
async function request(){
if(index === urls.length){
// 当前下标等于最后一个 结束
return
}
const i = index
// 保存序号 使result和urls对应
const url = urls[index]
index ++
console.log(url)
try {
const resp = await fetch(url)
result[i]=resp
} catch (err){
result[i] = err
} finally {
// 判断所有请求是否都完成了
if(count === urls.length) {
resolve(result)
}
request()
}
}
// maxNum 和 urls。length去最小进行调用
const times = Math.min(maxNum, urls.length)
for(let i=0;i<times.length;i++){
request()
}
})
},
requestSum(){
}
},