当前位置: 首页 > news >正文

合肥网站建设q479185700強沈阳seo排名收费

合肥网站建设q479185700強,沈阳seo排名收费,做网站外包价格,广州网站制作怎样webpack打包的基本原理 核心功能就是把我们写的模块化代码转换成浏览器能够识别运行的代码,话不多说我们一起来了解它 首先我们建一个空项目用 npm init -y 创建一个初始化的,在跟目录下创建src文件夹,src下创建index.js,add.js…

webpack打包的基本原理

核心功能就是把我们写的模块化代码转换成浏览器能够识别运行的代码,话不多说我们一起来了解它

首先我们建一个空项目用 npm init -y 创建一个初始化的,在跟目录下创建src文件夹,src下创建index.js,add.js,square.js,tip.js。在根目录下创建index.html
在这里插入图片描述
index.html引入index.js,index.js引入add.js、square.js。square.js引入tip.js

//add.js
export default (a, b) => {return a + b;
};//square.js
import tip from "tip.js";
const square = (a) => {console.log(tip);return a * a;
};
export { square };//tip.js
export default "我是提示-----";

index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body></body><script src="./src/index.js"></script>
</html>

运行index.html会报错,不能识别es6的模块化导入
在这里插入图片描述
让我们来实现webpack打包的核心功能

实现webpack打包核心功能

首先在根目录下建一个bundle.js用来对刚刚写的index.js进行打包
webpack官网对打包流程的介绍

it internally builds a dependency graph which maps every module your project needs and generates one or more bundles(webpack会在内部构建一个 依赖图(dependency graph),此依赖图会映射项目所需的每个模块,并生成一个或多个 bundle)

根据上面的说明进行分析,打包的工作基本流程如下

  1. 读取入口文件中的内容(也就是index.js文件)
  2. 分析入口文件,递归读取模块所依赖的文件 内容,生成依赖图
  3. 根据依赖图生成浏览器能运行的代码

1、处理单个模块内容

const fs = require("fs");
const getModuleInfo = (file) => {const body = fs.readFileSync(file, "utf-8");//获取文件内容,是字符串console.log(body);
};
getModuleInfo("./src/index.js");

打印出来是文件内容的字符串
在这里插入图片描述
借助安装@babel/parser 把,js文件代码转换成js对象,叫做抽象语法树(ast)

const fs = require("fs");
const parser = require("@babel/parser");
const getModuleInfo = (file) => {const body = fs.readFileSync(file, "utf-8");const ast = parser.parse(body, {//表示我们要解析的是es6模块sourceType: "module",});console.log(ast.program.body);
};
getModuleInfo("./src/index.js");

打印ast.program.body的结构:

[Node {type: 'ImportDeclaration', start: 0,end: 27,loc: SourceLocation {      start: [Position],       end: [Position],filename: undefined,     identifierName: undefined},specifiers: [ [Node] ],source: Node {type: 'StringLiteral',start: 16,end: 26,loc: [SourceLocation],extra: [Object],value: './add.js'}},Node {type: 'ImportDeclaration',start: 29,end: 66,loc: SourceLocation {start: [Position],end: [Position],filename: undefined,identifierName: undefined},specifiers: [ [Node] ],source: Node {type: 'StringLiteral',start: 52,end: 65,loc: [SourceLocation],extra: [Object],value: './square.js'}},Node {type: 'VariableDeclaration',start: 68,end: 90,loc: SourceLocation {start: [Position],end: [Position],filename: undefined,identifierName: undefined},declarations: [ [Node] ],kind: 'const'},Node {type: 'VariableDeclaration',start: 92,end: 114,loc: SourceLocation {start: [Position],end: [Position],filename: undefined,identifierName: undefined},declarations: [ [Node] ],kind: 'const'},Node {type: 'ExpressionStatement',start: 116,end: 143,loc: SourceLocation {start: [Position],end: [Position],filename: undefined,identifierName: undefined},expression: Node {type: 'CallExpression',start: 116,end: 142,loc: [SourceLocation],callee: [Node],arguments: [Array]}},Node {type: 'ExpressionStatement',start: 145,end: 172,loc: SourceLocation {start: [Position],end: [Position],filename: undefined,identifierName: undefined},expression: Node {type: 'CallExpression',start: 145,end: 171,loc: [SourceLocation],callee: [Node],arguments: [Array]}}
]

type属性是ImportDeclaration的节点,其source.value属性是引入这个模块的相对路径,上面打印出两个ImportDeclaration节点,说明对应的是入口文件中的两个import

对ast.program.body做处理,本质上是对这个数组遍历,循环做处理,借助安装@babel/traverse来完成这项工作

const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;const getModuleInfo = (file) => {//1、把入口文件字符串ast对象const body = fs.readFileSync(file, "utf-8");const ast = parser.parse(body, {//表示我们要解析的是es6模块sourceType: "module",});//2、获取类型为ImportDeclaration的所依赖模块的信息地址const deps = {};//创建一个对象deps,用来收集模块自身引入的依赖,用traverse遍历需要的ImportDeclaration节点做处理,把相对路径转成绝对路径traverse(ast, {ImportDeclaration({ node }) {const dirname = path.dirname(file);let absPath = "./" + path.join(dirname, node.source.value);absPath = absPath.replace("\\", "/");deps[node.source.value] = absPath;},});console.log(deps);
};
getModuleInfo("./src/index.js");

deps打印出入口文件引入的依赖地址
在这里插入图片描述
获取依赖后,需要对ast做语法转换,把es6转成es5的语法,安装@babel/core以及@babel/preset-env完成

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) => {//1、把入口文件字符串ast对象const body = fs.readFileSync(file, "utf-8");const ast = parser.parse(body, {//表示我们要解析的是es6模块sourceType: "module",});//2、获取类型为ImportDeclaration的所依赖模块的信息地址const deps = {};//创建一个对象deps,用来收集模块自身引入的依赖,用traverse遍历需要的ImportDeclaration节点做处理,把相对路径转成绝对路径traverse(ast, {ImportDeclaration({ node }) {const dirname = path.dirname(file);let absPath = "./" + path.join(dirname, node.source.value);absPath = absPath.replace("\\", "/");deps[node.source.value] = absPath;},});//3、把es6语法转换成es5const { code } = babel.transformFromAst(ast, null, {presets: ["@babel/preset-env"],});const moduleInfo = { file, deps, code };console.log(moduleInfo);return moduleInfo;
};
getModuleInfo("./src/index.js");

moduleInfo 打印结果为:
在这里插入图片描述
最终把一个模块的代码转化为一个对象形式的信息,这个对象包含文件的绝对路径,文件所依赖模块的信息,以及模块内部经过babel转化后的代码

接下去需要递归查找所有的模块,比如square.js里引用了tip.js。
这个过程也是获取依赖图(dependency graph)的过程

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) => {//1、把入口文件字符串ast对象const body = fs.readFileSync(file, "utf-8");const ast = parser.parse(body, {//表示我们要解析的是es6模块sourceType: "module",});//2、获取类型为ImportDeclaration的所依赖模块的信息地址const deps = {};//创建一个对象deps,用来收集模块自身引入的依赖,用traverse遍历需要的ImportDeclaration节点做处理,把相对路径转成绝对路径traverse(ast, {ImportDeclaration({ node }) {const dirname = path.dirname(file);let absPath = "./" + path.join(dirname, node.source.value);absPath = absPath.replace("\\", "/");deps[node.source.value] = absPath;},});//3、把es6语法转换成es5const { code } = babel.transformFromAst(ast, null, {presets: ["@babel/preset-env"],});const moduleInfo = { file, deps, code };return moduleInfo;
};//4、递归获取所有模块信息和之间的依赖关系
const parseModules = (file) => {//定义依赖图const depsGraph = {};// 首先获取入口的信息const entry = getModuleInfo(file);const temp = [entry];for (let i = 0; i < temp.length; i++) {const item = temp[i];const deps = item.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,};});console.log(depsGraph);return depsGraph;
};
parseModules("./src/index.js");

获得的depsGraph对象如下:

{file: './src/index.js',deps: { './add.js': './src/add.js', './square.js': './src/square.js' },code: '"use strict";\n' +'\n' +'var _add = _interopRequireDefault(require("./add.js"));\n' +'var _square = require("./square.js");\n' +'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n' +'var sum = (0, _add["default"])(2, 3);\n' +'var sqr = (0, _square.square)(4);\n' +'console.log("sum===", sum);\n' +'console.log("sqr===", sqr);'
}
PS C:\Users\keyuan04\Desktop\webpack> node bundle.js
{'./src/index.js': {deps: { './add.js': './src/add.js', './square.js': './src/square.js' },code: '"use strict";\n' +'\n' +'var _add = _interopRequireDefault(require("./add.js"));\n' +'var _square = require("./square.js");\n' +'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n' +'var sum = (0, _add["default"])(2, 3);\n' +'var sqr = (0, _square.square)(4);\n' +'console.log("sum===", sum);\n' +'console.log("sqr===", sqr);'},'./src/add.js': {deps: {},code: '"use strict";\n' +'\n' +'Object.defineProperty(exports, "__esModule", {\n' +'  value: true\n' +'});\n' +'exports["default"] = void 0;\n' +'var _default = function _default(a, b) {\n' +'  return a + b;\n' +'};\n' +'exports["default"] = _default;'},'./src/square.js': {deps: { 'tip.js': './src/tip.js' },code: '"use strict";\n' +'\n' +'Object.defineProperty(exports, "__esModule", {\n' +'  value: true\n' +'});\n' +'exports.square = void 0;\n' +'var _tip = _interopRequireDefault(require("tip.js"));\n' +'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }\n' +'var square = function square(a) {\n' +'  console.log(_tip["default"]);\n' +'  return a * a;\n' +'};\n' +'exports.square = square;'},'./src/tip.js': {deps: {},code: '"use strict";\n' +'\n' +'Object.defineProperty(exports, "__esModule", {\n' +'  value: true\n' +'});\n' +'exports["default"] = void 0;\n' +'var _default = "我是提示-----";\n' +'exports["default"] = _default;'}
}

我们最终得到的模块分析数据如上图所示,接下来,我们就要根据这里获得的模块分析数据,来生产最终浏览器运行的代码。

上面打印的依赖图可以看到,最终的code里包含exports以及require这样的语法,所以,我们在生成最终代码时,要对exports和require做一定的实现和处理,把依赖图对象中的内容转换成能够执行的代码,以字符串形式输出。 我们把整个代码放在自执行函数中,参数是依赖图对象
把取得入口文件 的code信息,去执行。使用eval函数执行。
最后把生成的内容写入到dist文件中

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) => {//1、把入口文件字符串ast对象const body = fs.readFileSync(file, "utf-8");const ast = parser.parse(body, {//表示我们要解析的是es6模块sourceType: "module",});//2、获取类型为ImportDeclaration的所依赖模块的信息地址const deps = {};//创建一个对象deps,用来收集模块自身引入的依赖,用traverse遍历需要的ImportDeclaration节点做处理,把相对路径转成绝对路径traverse(ast, {ImportDeclaration({ node }) {const dirname = path.dirname(file);let absPath = "./" + path.join(dirname, node.source.value);absPath = absPath.replace("\\", "/");deps[node.source.value] = absPath;},});//3、把es6语法转换成es5const { code } = babel.transformFromAst(ast, null, {presets: ["@babel/preset-env"],});const moduleInfo = { file, deps, code };return moduleInfo;
};//4、递归获取所有模块信息和之间的依赖关系
const parseModules = (file) => {//定义依赖图const depsGraph = {};// 首先获取入口的信息const entry = getModuleInfo(file);const temp = [entry];for (let i = 0; i < temp.length; i++) {const item = temp[i];const deps = item.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,};});console.log(depsGraph);return depsGraph;
};//生成最终代码
const bundle = (file) => {//把依赖图转字符串,放在自执行函数中执行const depsGraph = JSON.stringify(parseModules(file));return `(function(graph){function require(file){var exports = {};function absRequire(relPath){return require(graph[file].deps[relPath])}(function(require,exports,code){eval(code)})(absRequire,exports,graph[file].code)return exports}require('${file}')})(${depsGraph})`;
};const content = bundle("./src/index.js");
fs.rmdirSync("./dist", { recursive: true });
// 写入到dist/bundle.js
fs.mkdirSync("./dist");
fs.writeFileSync("./dist/build.js", content);

最后在index.html中入这个./dist/bundle.js,在控制台就可以看到正确的输出结果
在这里插入图片描述

http://www.qdjiajiao.com/news/7297.html

相关文章:

  • 网站建设与管理教材爱站网反链查询
  • 惠州做网站 百度优化最新实时新闻
  • 聚美优品网站建设友情链接的作用大不大
  • 做电影网站用什么软件叫什么百度上海推广优化公司
  • 怎么做外围网站的代理网站收录情况
  • php网站开发数据列表排重百度app交易平台
  • 柳州建设网app成都seo正规优化
  • 做网站 美国服务器哪里好品牌推广渠道有哪些
  • 做网站上传图片百度高级搜索页面
  • 免费网站设计 优帮云seo优化软件有哪些
  • 中国空间站有多大seo快速排名工具
  • 免费网站下载直播软件如何让网站快速收录
  • 网站建设url厦门网站流量优化价格
  • 网站内容北京百度关键词优化
  • 珍珠奶茶网站建设营销网络的建设
  • 苏州工业园区一站式服务中心网络营销策划推广
  • 个人备案 做政府网站seo搜索引擎优化期末及答案
  • 网站 建设阶段营销推广网站
  • 莱芜博客网淘宝优化关键词的步骤
  • 重庆网站设计公司优化设计三年级上册答案
  • 滤芯网站怎么做聊城网站推广的公司
  • 做宠物网站需要实现什么功能网站注册流程
  • 南宁网站建设推广优化金戈枸橼酸西地那非片
  • 无锡市城乡建设局网站如何快速推广网上国网
  • 网站怎么做评估seo优化一般包括哪些内容()
  • 网站cms模板域名购买平台
  • 那个网站做创意图比较好网站目录提交
  • 查看网站空间弹窗广告最多的网站
  • 网站qq客服代码百度的网址是什么呢
  • 网站建设流程方案网页模板代码