模块化
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⽅法:
- 1. 我们⾸先传⼊主模块路径
- 2. 将获得的模块信息放到temp数组⾥。
- 3. 外⾯的循坏遍历temp数组,此时的temp数组只有主模块
- 4. 循环⾥⾯再获得主模块的依赖deps
- 5. 遍历deps,通过调⽤getModuleInfo将获得的依赖模块信息push到 temp数组⾥。`
5) 使得引⼊的代码可以被执⾏最终需要处理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 和 json
webpack不具备这些功能 通过插件完成
手写实现webpack
webpack的核心概念
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 理解原理完整代码
// 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].depsif(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 的命令
控制并发请求数量
// 并发控制: 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(){}},