基础知识
认识node的魔力很重要
脱离浏览器下运行js
node最大的作用之一,就是让你在脱离浏览器的情况下运行js。一般js只能运行在浏览器上。
但node可以让你在脱离浏览器的情况下,写js,这点非常重要。
提供底层操作能力
除此之外,node还提供了很多能力,让你通过js就可以操作cpu,内存,读写文件 这些以前后端才能做的底层的操作能力。
中间层:服务器中负责IO读写的中间层服务器
待完善。
把玩node的技巧
使用commonjs而不用import
node可以识别commonjs规范,但不能识别import es6。
在自己玩一玩node的时候,使用commonjs而不用import,避开webpack babel ts 等等干扰。
commonjs畅通无阻
如果玩一玩node,使用commonjs可以用得很爽。
可以写个小js打印下node的各种模块变量
排除其他比如 webpack babel 等干扰,写一个小js,js中打印以下node的各种模块,比如 __dirname等等。
全局模块
好用的process.argv
process.argv可以获取控制台命令的参数。
比如在控制台输入1
node ./src/app.js node -v
js中 console.log(process.argv) 就是:1
2
3
4[ '/usr/local/bin/node',
'/Users/js/Desktop/work/git/learns/sequelize-demo/src/app.js',
'node',
'-v' ]
你在js中获取到命令中最后两个参数是node 和 -v 后,就判定用户想知道版本号,那么就在js中console.log的方式打印版本号出来,在cmd中将会看到打印出来的版本号。
这只是其中一个例子,你可以以此类推,可以自己写一些命令工具。
__dirname在编译和未编译的js中的区别
在没有编译的地方dirname就是文件当前的目录;
如果这个文件是webpack将会被编辑的,一般是前端业务js,此时的dirname是webpack编译完成后的js所处文件的目录,也可能这个js经过webpack编译后,被合并到一个统一的versor.js文件中,此时__dirname就是此文件目录。
系统模块
指的是需要require,但不需要下载的模块,比如path模块。
exports 与 module.exports
优先用module.exports
1 | exports.a = 1; |
不过导出时一般用 module.exports;
区别
1 | class girl { |
http.createServer
listen
http.createServer表明启了一个服务,光一个服务还不行,你需要告诉我端口,因为服务的完整地址肯定包括端口。
下面的listen的意思1
2
3
4const http = require('http');
http.createServer(()=>{
console.log('我来了')
}).listen(8000)
res req
接着上面,既然访问了服务器,那么肯定要给一定响应,不然访问者就会一致访问且等待。
因此就有了req,res。1
2
3
4
5
6
7
8
9
10
11const port = 3000;
http.createServer((req,res)=>{
const file = req.url.replace('/','') || 'test.html'
fs.readFile(path.resolve(__dirname,file), (err, data)=>{
if(err){
res.writeHead(404);
res.end('404 not found')
}
res.end(data)//可以读取图片或html
})
}).listen(port, ()=>console.log(`open port ${port}`))
在浏览器中显示html或图片
参考《res req》,demo看参考里面。
demo
设置不同响应头类型,html显示不一样
1 | const port = 3000; |
这里是一个demo 参看 typeApp.js,表现了不同响应头类型后,html在浏览器上显示效果不一样,一个以txt文件渲染,一个以html实际解析效果渲染
res.writeHead设置响应头
参考《设置不同响应头类型,html显示不一样》
黑知识
npm install 与 yarn install 的差异
node_module内的包的说明信息内容不同
可以自己试验用两种方式安装的包,看看最终node_module内此包内容是有差异的,源码功能是一致的。
路径中的 **
与 *
1 | "src/**/*.test.tsx",// 两个**匹配任意长度任意路径下 |
神奇的相对路径
报错not suce file
已知 test.md的路径为:1
./sequelize-demo/src/test.md
已知 app.js的路径为:1
./sequelize-demo/src/app.js
app.js的代码为:1
2
3
4
5const fs = require('fs')
fs.readFile('./test.md',(err,data)=>{
console.log(err)
console.log(data.toString())
})
那么在根目录下执行命令:1
node ./sequelize-demo/src/app.js
会报错 找不到 ./test.md 这个文件。
解决方式一
原来是因为readFile的相对地址,不是以 app.js所在目录作为参考的,而是以执行node命令的目录为参考的。
因为我们是在根目录下执行node命令,因此需要修改readFile地址如下,就可以正常了:1
2
3
4fs.readFile('./sequelize-demo/src/test.md',(err,data)=>{
console.log(err)
console.log(data.toString())
})
解决方式二(推荐)
上面的相对地址容易出问题,在此推荐以绝对路径来处理:1
2
3
4
5
6
7const fs = require('fs')
const path = require('path')
fs.readFile(path.resolve(__dirname,'test.md'),(err,data)=>{
console.log(err)
console.log(data.toString())
})
如果同在根目录就没有此异常
如果上面的app.js在根目录下,就不会出现上面的问题,原因参考《解决方式一》
JSON.stringify与toString使用
JSON.stringify输出内容的二进制
1 | fs.readFile(pa,(err,data)=>{ |
toString可输出字符串的Buffer二进制流
如果我们知道这个二进制流Buffer是一个字符串,那么可以使用toString来解析成字符串。
toString输出正常内容
参考上面《JSON.stringify输出内容的二进制》《toString可输出字符串的Buffer二进制流》
读取文件内容推荐toString
参考上面《JSON.stringify输出内容的二进制》
require的路径
- 如果有路径,就去路径里面找 – require(‘./ph.js’)
- 没有路径就去 node_modules里面找 – require(‘./react’)
- 如果node_modules没有,就去node的全局安装目录找
webpack编译时可使用fs,页面js中不行,why?
原来,node script 进行webpack编译的时候,其实是基于node环境的:1
"start": "npx webpack-dev-server --config webpack.dev.js"
node script 本身就是基于node环境的,所以能够在webpack.dev.js中使用node的各种模块。
由webpack编译出来的html,放在webpack的devServe服务器上,我们才可以通过浏览器访问。
webpack编译完后会启动一个本地服务,因此从我们通过浏览器访问页面开始,我们所使用的环境已经不是node了,从编译完后,node的工作基本上就结束了。
运行在浏览器上的html,其运行环境是浏览器,非node环境,因此html不能获取node模块的各种包,当然了,也不排除webpack将node的一些包内置给html,
不过从目前看,fs是没有内置到html上的。
小结下:编译环境是运行在node上,html文件是运行在浏览器上,前者具备node各个模块,后者不具备。
为什么前端工程化都使用node
node让js脱离浏览器运行成为可能
前端工程化需要对前端文件进行压缩打包,需要提供前端开发环境或实时编译的开发模式。
要实现上面的文件压缩打包,就必然用到对文件的读写能力;
要提供开发环境或模式,就必然需要启动服务;
对文件的读写,你可以使用很多其他语言,比如java等等。
但一个前端人员肯定希望js能够做到底层操作,而node满足了这点。
原本js是运行在浏览器上的一门语言,脱离浏览器就能运行了。
而上面的编译或者提供服务器功能,都是在非浏览器环境下的。
因此在node出现前,上面的这些功能若使用js完全是不可能。
node为js提供了很多底层操作能力
node提供了fs文件操作能力,提供了http服务器能力,还有很多其他功能,如操作系统内存等等。
在node环境下,js具备了操作底层的能力,而这些在浏览器下js所不具备的。
强大的npm生态
node提供了强大的npm生态,各种高手可以开发一个npm包,然后在node或js中运行。
小结
基于以上,所以一般前端工程化(编译阶段),包括js的后端工程化基本上都是基于node(基于npm)
node后端工程的业务js都有node功能
与前端工程化不一样的是,前端一般只有编译阶段的代码具有node的环境。
node后端工程,包括后端工程的编译以及后端工程的接口业务逻辑代码,都是运行在node环境下的,都能使用node模块。
后端工程中的代码,无论编译和运行都是在node环境内,都具有node模块能力,如果不是这样,为什么后端能够到处使用express或koa来写接口逻辑呢。因为express是一个抽象了原生nodejs的框架。
node调试
参考另外一篇博客《vscode笔记 - vscode调试》
解决npm unlink问题
调试的时候,如果使用了npm link,
最后真正要全局 npm i -g npm包 时,可能报错,
解决方法如下:1
2
3
4
5
6
7470 which npm
471 cd /c/Program Files/nodejs
472 cd '/c/Program Files/nodejs'
473 start .
474 ls | grep ol
475 rm -rf olg.cmd olg.ps1* olg*
476 npm i -g npm包名
调试npm link问题想到的npm调试经验
过程描述
npm link river-compass 时报错,但报错信息比较简单难以定位问题。1
2
3
4
5
6
7
8$ npm link river-compass
// 报错......
error Cannot read properties of null (reading 'package')
verbose exit 1
npm ERR! A complete log of this run can be found in:
// 这个日志文件有详细解释
npm ERR! C:\Users\YeWills\AppData\Local\npm-cache\_logs\2022-03-30T09_34_26_992Z-debug.log
于是查看详细日志信息:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36$ cat 'C:\Users\YeWills\AppData\Local\npm-cache\_logs\2022-03-30T09_34_26_992Z-debug.log'
0 verbose cli [
0 verbose cli 'C:\\Program Files\\nodejs\\node.exe',
0 verbose cli 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
0 verbose cli 'link',
0 verbose cli 'river-compass'
0 verbose cli ]
// ......
28 timing command:link Completed in 31608ms
29 verbose stack TypeError: Cannot read properties of null (reading 'package')
# 知道错误在 这里报出来的
# 我用的是vscode,执行命令都是在此项目的vscode下打开的 终端,
# 在此终端执行 cat 命令,显示这些内容,
# window电脑下,按住 ctrl + click下面的文件路径,【其实你也可以直接将文件放在此vscode打开】
# 此文件将在当前vscode被打开
# 打开debug模式下的终端,在此文件上断点,
# 再次运行npm link river-compass 命令,调试发现,报错时出现了一个无用的xnbzvdev npm 包,把这个包删除后发先npm link 成功了
# 问题完美解决
29 verbose stack at Link.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:709:35)
29 verbose stack at Node.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:775:20)
29 verbose stack at Link.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:783:19)
29 verbose stack at Node.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:775:20)
29 verbose stack at Node.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:775:20)
29 verbose stack at Node.set root [as root] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:775:20)
29 verbose stack at Node.set parent [as parent] (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\node_modules\@npmcli\arborist\lib\node.js:1176:19)
29 verbose stack at Link.missingArgsFromTree (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\lib\link.js:201:19)
29 verbose stack at Link.missingArgsFromTree (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\lib\link.js:177:19)
29 verbose stack at Link.linkInstall (C:\Users\YeWills\AppData\Roaming\nvm\v16.13.2\node_modules\npm\lib\link.js:103:26)
29 verbose stack at processTicksAndRejections (node:internal/process/task_queues:96:5)
30 verbose cwd D:\workplace\webpack\webpack-modify-demo
31 verbose Windows_NT 10.0.19044
32 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "link" "river-compass"
33 verbose node v16.13.2
34 verbose npm v8.1.2
35 error Cannot read properties of null (reading 'package')
36 verbose exit 1
以后npm命令使用时,出现任何问题,可以通过这种方式调试。
npm其实就是一个全局安装的npm包,其他任何全局安装的npm包,都可通过此方式调试。
重视npm log文件
参考如上
调试npm全局包的方法
参考《调试npm link问题想到的npm调试经验》