npm link
说明
npm link: 本地调试 npm 模块
npm-sum (npm包)
项目结构
mkdir npm-sum
npm init -y
touch index.js
复制代码
//index.js
const sum = (...args) => {
return args.reduce((prev, next) => prev + next, 0)
}
module.exports = sum
复制代码
npm link
方式将本地开发包链接到全局 node_modules/下
报错
权限问题
解决方法,用管理员权限打开power shell
example (测试项目)
项目结构
mkdir example
npm init -y
touch index.js
复制代码
//index.js
const sum = require('npm-sum')
console.log(sum(1, 2, 3, 4, 5))
复制代码
npm link npm-sum
安装本地npm包(npm-sum),到自己的项目下,会生成在node_modules
下
运行项目
node index.js
复制代码
与npm-sum解除关联
npm unlink npm-sum
复制代码
参考
原生webpack
最简单的webpack怎么运行的
目录结构
初始化
npm init -y
cnpm install webpack webpack-cli -D
复制代码
src
// src/base/b.js
module.exports = 'b'
复制代码
// src/a.js
let b = require('./base/b.js')
module.exports = 'a' + b
复制代码
// src/index.js
let str = require('./a.js')
console.log(str)
复制代码
webpack.config.js
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {},
plugins: []
}
复制代码
运行
根目录下运行命令
webpack
复制代码
浏览器中查看
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="https://juejin.cn/post/bundle.js"></script>
</body>
</html>
复制代码
实现自己的webpack
初始化
webpack-dev(项目)
mkdir webpack-dev
npm init -y
复制代码
zf-pack(类似webpack的npm包)
mkdir zf-pack
npm init -y
复制代码
修改package.json
//package.json
{
"name": "zf-pack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
//新增
"bin": {
"zf-pack": "./bin/zf-pack.js"
}
}
复制代码
新增bin
bin/zf-pack.js
#! /usr/bin/env node
console.log('start')
复制代码
关联运行
zf-pack
cd zf-pack //管理员权限
npm link
复制代码
webpack-dev
npm link zf-pack
npx zf-pack
复制代码
zf-pack拿到webpack-dev中的代码
webpack-dev
webpack.config.js
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {},
plugins: []
}
复制代码
src目录
// src/base/b.js
module.exports = 'b'
复制代码
// src/a.js
let b = require('./base/b.js')
module.exports = 'a' + b
复制代码
// src/index.js
let str = require('./a.js')
console.log(str)
复制代码
zf-pack
bin
// /bin/zf-pack.js
#! /usr/bin/env node
// console.log('start')
let path = require('path')
// // config配置文件
let config = require(path.resolve('webpack.config.js'))
let Compiler = require('../lib/Compiler.js')
let compiler = new Compiler(config)
// 标识运行编译
compiler.run()
复制代码
lib
// lib/Compiler.js
let fs = require('fs')
let path = require('path')
class Compiler {
constructor (config) {
// entry output
this.config = config
// 需要保存入口文件的路径
this.entryId // './src/index.js'
// 需要保存所有的模块依赖
this.modules = {}
this.entry = config.entry // 入口路径
// 工作路径
this.root = process.cwd()
}
getSource (modulePath) {
let content = fs.readFileSync(modulePath, 'utf8')
return content
}
buildModule (modulePath, isEntry) {
let source = this.getSource(modulePath)
// 模块id modulePath = modulePath- this.root src/index.js
let moduleName = './' + path.relative(this.root, modulePath)
console.log('source', source)
console.log('moduleName', moduleName)
}
run () {
this.buildModule(path.resolve(this.root, this.entry), true)
}
}
module.exports = Compiler
复制代码
重新发布运行
zf-pack
npm link
复制代码
webpack-dev
npm link zf-pack
npx zf-pack
复制代码
AST递归解析
安装依赖
cnpm install babylon @babel/types @babel/traverse @babel/generator -S
复制代码
增加parse方法
let fs = require('fs')
let path = require('path')
let babylon = require('babylon')
let t = require('@babel/types')
let traverse = require('@babel/traverse').default
let generator = require('@babel/generator').default
class Compiler {
constructor (config) {
// entry output
this.config = config
// 需要保存入口文件的路径
this.entryId // './src/index.js'
// 需要保存所有的模块依赖
this.modules = {}
this.entry = config.entry // 入口路径
// 工作路径
this.root = process.cwd()
}
getSource (modulePath) {
let content = fs.readFileSync(modulePath, 'utf8')
return content
}
parse (source, parentPath) {
let ast = babylon.parse(source)
let dependencies = [] // 依赖的数组
traverse(ast, {
CallExpression (p) {
// a() require()
let node = p.node // 对应的节点
if (node.callee.name === 'require') {
node.callee.name = '__webpack_require__'
let moduleName = node.arguments[0].value // 取到的就是模块的引用名字
moduleName = moduleName + (path.extname(moduleName) ? '' : '.js')
moduleName = './' + path.join(parentPath, moduleName)
;('src/a.js')
dependencies.push(moduleName)
node.arguments = [t.stringLiteral(moduleName)]
}
}
})
let sourceCode = generator(ast).code
return { sourceCode, dependencies }
}
buildModule (modulePath, isEntry) {
let source = this.getSource(modulePath)
// 模块id modulePath = modulePath- this.root src/index.js
let moduleName = './' + path.relative(this.root, modulePath)
if (isEntry) {
this.entryId = moduleName // 保存入口的名字
}
// 解析需要把source源码进行改造 返回一个依赖列表
let { sourceCode, dependencies } = this.parse(
source,
path.dirname(moduleName)
) // ./src
console.log(sourceCode, dependencies)
// 把相对路径和模块中的内容 对应起来
this.modules[moduleName] = sourceCode
dependencies.forEach(dep => {
// 附模块的加载 递归加载
this.buildModule(path.join(this.root, dep), false)
})
}
run () {
this.buildModule(path.resolve(this.root, this.entry), true)
}
}
module.exports = Compiler
复制代码
运行
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END