I/O处理(fs)
1. 同步调用readFileSync
const fs = require('fs');
// 同步调用
const data = fs.readFileSync('./conf.js'); //代码会阻塞在这里
console.log(data);
2. 异步调用readFile
const fs = require('fs');
// 异步调用
fs.readFile('./conf.js', (err, data) => {
if (err) throw err;
console.log(data);
})
3. promisify
const fs = require('fs');
const {promisify} = require('util')
const readFile = promisify(fs.readFile)
readFile('./conf.js').then(data=>console.log(data))
4. promisify API
const fsp = require("fs").promises;
fsp
.readFile("./confs.js")
.then(data => console.log(data))
.catch(err => console.log(err));
5. async/await
(async () => {
const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
const data = await readFile('./index.html')
console.log('data',data)
})()
Buffer缓冲区(Buffer类似数组,所以很多数组方法它都有)
读取数据类型为Buffer,Buffer - 用于在 TCP 流、文件系统操作、以及其他上下文中与八位字节流进行交互。 八位字节组 成的数组,可以有效的在JS中存储二进制数据
1. Buffer.alloc创建字节
// 创建一个长度为10字节以0填充的Buffer
const buf1 = Buffer.alloc(10);
console.log(buf1);
2. Buffer.from
// 创建一个Buffer包含ascii.
// ascii 查询 http://ascii.911cha.com/
const buf2 = Buffer.from('a')
console.log(buf2,buf2.toString())
// 创建Buffer包含UTF-8字节
const buf3 = Buffer.from('Buffer创建方法');
console.log(buf3);
3. write写入数据
const buf1 = Buffer.alloc(10); // 创建Buffer
buf1.write('hello'); // 写入Buffer数据
console.log(buf1);
4. toString()读取Buffer数据
onst buf3 = Buffer.from('Buffer创建方法');
console.log(buf3.toString()); //// 读取Buffer数据
5. concat合并Buffer
const buf4 = Buffer.concat([buf1, buf3]);
console.log(buf4.toString());
http服务
1.创建一个http服务器
const http = require('http');
const http = require('http');
const server = http.createServer((request, response) => {
console.log('there is a request');
response.end('a response from server');
});
server.listen(3000);
接口
1. 显示一个服务端页面
const {url, method} = request; //请求的地址和方法
if (url === '/' && method === 'GET') {
fs.readFile('index.html', (err,data) => {
if(err) {
response.writeHead(500, { 'Content-Type':'text/plain;charset=utf-8' })
response.end('500,服务器错误');
return
}
response.statusCode = 200; // 设置返回状态码
response.setHeader('Content-Type', 'text/html'); // 设置返回数据格式
response.end(data);
})
} else {
response.statusCode = 404;
response.setHeader('Content-Type', 'text/plain;charset=utf-8'); response.end('404, 页面没有找到');
}
2. 接着编写一个接口
else if (url === '/users' && method === 'GET') {
response.writeHead(200, { 'Content-Type': 'application/json' });
response.end(JSON.stringify([{name:'tom',age:20}]));
}
Stream流
stream - 是用于与node中流数据交互的接口
1. fs.createReadStream->fs.createWriteStream->pipe
//二进制友好,图片操作
const fs = require('fs')
const rs2 = fs.createReadStream('./01.jpg')
const ws2 = fs.createWriteStream('./02.jpg')
rs2.pipe(ws2);
2. 响应图片请求
const {url, method, headers} = request;
else if (method === 'GET' && headers.accept.indexOf('image/*') !== -1) {
fs.createReadStream('.'+url).pipe(response);
}
备注:
- Accept代表发送端(客户端)希望接受的数据类型,比如:Accept:text/xml; 代表客户端希望 接受的数据类型是xml类型。
- Content-Type代表发送端(客户端|服务器)发送的实体数据的数据类型。 比如:Content- Type:text/html; 代表发送端发送的数据格式是html。
- 二者合起来, Accept:text/xml; Content-Type:text/html ,即代表希望接受的数据类型是xml格 式,本次请求发送的数据的数据格式是html。
CLI工具
1. 创建工程
mkdir vue-auto-router-cli
cd vue-auto-router-cli
npm init -y
npm i commander download-git-repo ora handlebars figlet clear chalk open -s
// download-git-repo 实现clone
// ora 下载进度条,loading状态提示
// commander 定制命令
// figlet把小的文字放大
// clear 清屏
// chalk 设置彩色cmd
// open 自动打开浏览器
2. 自定义bin文件---bin/candy.js
// 指定脚本解释器为node
#!/usr/bin/env node
console.log('cli.....')
3. 配置package.json
// 当执行candy的时候,指向./bin/candy.js
"bin": {
"candy": "./bin/candy.js"
},
4. npm link,将npm模块链接到对应的运行项目中去(一定要link,否则找不到自定义命令)
cd vue-auto-router-cli
执行
npm link
5. 在cmd执行candy,就会运行candy.js的代码
6. 定制命令行界面---candy.js
#!/usr/bin/env node
// 指定脚本解释器为node
引入commander包
const program = require('commander')
// 这里就是配置我们输入candy -v显示版本号
program.version(require('../package').version)
// program.command用于定制命令
program
.command('init <name>') // 初始化一个xxx的文件
.description('init project') // 文件描述
.action(name => { // 功能,初始化打开欢迎界面
require('../lib/init')
})
// 固定写法,解析输入的参数
program.parse(process.argv)
7. 打开欢迎界面---lib/init.js
const {promisify} = require('util')
const figlet = promisify(require('figlet'))
const clear = require('clear')
const chalk = require('chalk')
const log = content => console.log(chalk.green(content))
module.exports = async name => {
// 打印欢迎画面
clear()
const data = await figlet('Candy Welcome') log(data)
}
8. 克隆脚手架---lib/download.js
const {promisify} = require('util')
module.exports.clone = async (repo,desc) => {
// repo 克隆地址
// desc 下载到哪个目录下
const download = promisify(require('download-git-repo'))
const ora = require('ora')
const process = ora(`下载.....${repo}`)
// 启动进度条
process.start()
await download(repo, desc)
// 启动成功
process.succeed()
}
---修改/lib/init.js
const {clone} = require('./download')
module.exports.init = async name => {
log('🚀创建项目:' + name)
// 从github克隆项目到指定文件夹
await clone('github:su37josephxia/vue-template', name)
}
9. 安装依赖---直接在init里面封装一个子进程
// promisiy化spawn
// 对接输出流
const spawn = async (...args) => {
// 启动一个子进程
const { spawn } = require('child_process')
// 封装一个promise
return new Promise(resolve => {
// 执行需要执行的命令args
const proc = spawn(...args)
// proc子进程产生正常的数据流跟主进程对接pipe
proc.stdout.pipe(process.stdout)
// proc子进程产生异常的数据流跟主进程对接pipe
proc.stderr.pipe(process.stderr)
proc.on('close', () => {
resolve()
})
})
}
module.exports.init = async name => {
log('安装依赖')
// 安装依赖
// cnpm 命令
// 第二个参数可以放很多,所以是个数组
// cwd 指定运行的路径
await spawn('cnpm', ['install'], { cwd: `./${name}` })
// 打印一个完成的标识
log(`
👌安装完成:
To get Start:
===========================
cd ${name}
npm run serve
===========================
`)
}
10.配置自启动项目
const open = require("open")
module.exports.init = async name => {
// ...
// 打开浏览器
open(`http://localhost:8080`);
await spawn('cnpm', ['run', 'serve'], { cwd: `./${name}` })
}
11.执行命令,创建一个test工程并初始化,最后自动打开浏览器窗口
candy init test
12. 完整的初始化代码----init.js
const {promisify} = require('util')
const figlet = promisify(require('figlet'))
const clear = require('clear')
const chalk = require('chalk')
const {clone} = require('./download')
const spawn = async (...args) => {
// 启动一个子进程
const {spawn} = require('child_process')
// 封装一个promise
return new Promise(resolve => {
// 执行需要执行的命令args
const proc = spawn(...args)
// proc子进程产生正常的数据流跟主进程对接pipe
proc.stdout.pipe(process.stdout)
// proc子进程产生异常的数据流跟主进程对接pipe
proc.stderr.pipe(process.stderr)
proc.on('close', () => {
resolve()
})
})
}
const log = content => console.log(chalk.green(content))
module.exports = async name => {
// 打印欢迎画面
clear()
const data = await figlet('Candy Welcome')
log(data)
// 创建项目
log(`🚀创建项目:` + name)
// 克隆代码
await clone('github:su37josephxia/vue-template', name)
log('安装依赖')
// cnpm 命令
// 第二个参数可以放很多,所以是个数组
// cwd 指定运行的路径
await spawn('cnpm', ['install'], {cwd: `./${name}`})
log(`
👌安装完成:
To get Start:
===========================
cd ${name}
npm run serve
===========================
`)
const open = require('open')
open('http://localhost:8080')
await spawn('npm', ['run', 'serve'], {cwd: `./${name}`})
}
实现自动生成路由表,自动生成菜单
- loader 文件扫描
- 代码模板渲染 hbs Mustache风格模板
1.编写自动生成模板 ----lib/refresh.js
const fs = require('fs')
// 引入模板库引擎
const handlebars = require('handlebars')
// 引入粉笔工具
const chalk = require('chalk')
// 输出一个新的函数
module.exports = async () => {
// 获取页面列表
const list =
// fs同步读目录
fs.readdirSync('./src/views')
.filter(v => v !== 'Home.vue')
.map(v => ({
name: v.replace('.vue', '').toLowerCase(),
file: v
}))
// 生成路由
compile({list}, './src/router.js', './template/router.js.hbs')
// 生成菜单
compile({list}, './src/App.vue', './template/App.vue.hbs')
/**
*
* @param {*} meta 数据定义
* @param {*} filePath 目标文件
* @param {*} templatePath 模板文件
*/
function compile(meta, filePath, templatePath) {
// 判断模板文件是否存在
if (fs.existsSync(templatePath)) {
// 同步读取文件
const content = fs.readFileSync(templatePath).toString()
// 生成编译后的结果
const reslut = handlebars.compile(content)(meta)
// 同步写入文件
fs.writeFileSync(filePath, reslut)
}
console.log(chalk.red(`🚀${filePath} 创建成功`))
}
}
2. 定义一个新的命令----bin/candy.js
program
.command('refresh')
.description('refresh routers...')
.action(require('../lib/refresh'))
监听变化
1.类似于热更新的功能---lib/serve.js
const spawn = (...args) => {
const { spawn } = require('child_process');
const proc = spawn(...args)
proc.stdout.pipe(process.stdout)
proc.stderr.pipe(process.stderr)
return proc
}
module.exports = async () => {
const watch = require('watch')
let process
let isRefresh = false
watch.watchTree('./src', async (f) => {
if (!isRefresh) {
isRefresh = true
process && process.kill()
await require('./refresh')()
setTimeout(() => { isRefresh = false }, 5000)
process = spawn('npm', ['run', 'serve'])
}
})
}
2. 定义一个新的命令----bin/candy.js
program
.command('serve')
.description('serve')
.action(require('../lib/serve'))
发布npm
1.根目录生成----publish.sh
#!/usr/bin/env bash
npm config get registry # 检查仓库镜像库
npm config set registry=http://registry.npmjs.org
echo '请进行登录相关操作:'
npm login # 登陆
echo "-------publishing-------"
npm publish # 发布
npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像 echo "发布完成"
exit
2. 执行
npm publish