nodejs from actual combat to entry

foreword

Many people learn node.js, but they still have a half-knowledge after learning it. They feel that they have learned it but have not fully learned it. When they want to use it in a project, they still have a feeling of being unable to start. This article mainly explains the application of node.js in actual projects to beginners through several practical examples, and uses as simple code as possible to make something first to improve beginners' confidence in learning. If you want to study in depth, you still need to focus on the official website, and you can also find some books to assist, such as "node. etc., and then dabble in various projects.

This article does not talk about basic knowledge, but focuses on actual combat. For students who have not learned node.js, you can spend half an hour or an hour browsing the introductory tutorial on the official website (the third section of this article has a little suggestion). What is wrong with this article? The place, welcome to correct me.

All code git address in this article: https://gitee.com/liaofeiyu/node-study, copy or poke here

1. What can nodejs do?

What is nodejs? The official website says this: Node.js is an open source and cross-platform JavaScript runtime environment . In other words, nodejs is just an environment for running JavaScript, providing some internal methods. What it can do depends entirely on the user.

We often use nodejs to do the following things:

  1. As a back-end server,
    this is not mentioned, whether it is the official website or a book, it is all about this. But there are many and cheap back-end talents, why spend a lot of money to find a node.js master? What's more, few operations and maintenance understand node, you have to teach operation and maintenance deployment, and if you go too far, you have to write docker yourself (the blogger's painful experience), or get off work early to play with your girlfriend (dog head).
  2. Used as middleware.
    Because js is much more convenient to process json data than other back-end languages ​​(such as java), some companies will add a node service between the back-end and the front-end for data processing, and return the most comfortable data format for the front-end to use. Let the front and back ends work more happily. However, there is an extra middleman to make the price difference, and the cost will go up immediately, so ordinary companies do not have this layer.
  3. As a front-end build tool - such as webpack
  4. Self-made efficiency tools
    For example, if you get an excel, you need to convert it into json and put it in a local static file. You may not find a suitable tool on the Internet, so it is also very good to write a node.js tool to process it (don't say python, js is the best language).

2. Use nodejs to make personal efficiency tools

After reading so much text, let's relax by writing some code first.

process excel


It is more convenient for node processing excel to use node-xlsx to parse. Using nodemon can save you from reinstalling node xx.js every time you change js

npm install node-xlsx
npm install nodemon -g

The example is relatively simple, just paste the code directly

const xlsx = require('node-xlsx')
const fs=require('fs');
let file = 'demo.xlsx'
// __dirname是当前目录,node全局变量之一
let path = `${
      
      __dirname}/input/${
      
      file}`;
// excel处理
const xlsxToXlsx = (path) => {
    
    
    //表格解析
    let sheetList = xlsx.parse(path);
    //对数据进行处理
    sheetList.forEach((sheet) => {
    
    
        sheet.data.forEach((row, index) => {
    
    
            // 第一行是标题 不处理
            if(index == 0){
    
    
                row[3] = '新的列'
                return;
            }
            // 加一列
            row[3] = row[2] + row[1]
        })
    })

    // xlsx将对象转成二进制流
    let buffer = xlsx.build(sheetList);
    // 写入
    fs.writeFile(path.replace(/input/, 'output').replace(/\./, '修改版.'), buffer, (err) => {
    
    
        if (err) {
    
     console.log(err); }
    });
}
xlsxToXlsx();

Process excel data and convert it into json

const xlsx = require('node-xlsx')
const fs=require('fs');
let file = 'demo.xlsx'
let path = `${
      
      __dirname}/input/${
      
      file}`;
// excel转json
const xlsxToJson = (path) =>{
    
    
    //表格解析
    let sheetList = xlsx.parse(path);
    // 拿到第一个sheet数据
    let sheet = sheetList[0].data
    let ret = [];
    sheet.forEach((row, index) => {
    
    
        // 第一行是标题 不处理
        if(index == 0){
    
    
            return;
        }
        // 已经知道每一列是什么了,直接按索引拿
        ret.push({
    
    
            city: row[0],
            code: row[1],
            name: row[2]
        })
    })
    // 转成字符串
    let str = JSON.stringify(ret);
    console.log(str)
    // 写入
    fs.writeFile(path.replace(/input/, 'output').replace(/\.xlsx/, '.json'), str, (err) => {
    
    
        if (err) {
    
     console.log(err); }
    })
}
xlsxToJson(path);

Return mock data as a mock server

Brazenly recommend my first blog: several front-end simulation data usage schemes

insert image description here

3. Introductory tutorial on node official website

注意:仅限于第一次浏览需要关注的点,有学过基础的就跳过吧
1. Run and exit
node xx, js run
ctrl+c to exit,
use processs.exit(0) to exit in the
code 2, parameters are related - just remember the following code

// 读取环境变量
process.env.NODE_ENV 
// 命令行输入传参
node my.js --name=joe --param2=abcdefg
// 代码中取参数,可以自己打印出来看看为什么是slice(2)
const args = require('minimist')(process.argv.slice(2))
args['name'] // joe
args['param2'] // abcdefg

3、consle

// 调试
consle.log();
// 记录错误日志----服务器开发用
console.error()
// 查看代码执行调用了哪些函数----定位错误很有用
console.trace()
// 代码执行时间----看代码性能
time()
timeEnd()

4. Receive input from the command line----vue-cli will talk about it.
5. REPL ---- input node on the command line, and then you can write js in the command tool, most people don't do
this
7. pacakge.json--configuration items that need to be looked at carefully.
9. Event loop--if you don't understand it, it won't affect your use of node. If you don't understand it well enough, it's useless. Learn to deal with interviews first, learn slowly, and you will understand later.
process.nextTick(), setImmediate() can also be understood first.
The little knowledge introduced: in timers and promis, non-grammatical errors will not affect your other code execution, try to use try catch in node.
10. Timer, promise, async, await - this is what you should know
about
js ---For building a server, let's see the actual combat directly
13. File system----the api document is too long, directly flip the document in actual combat
14. Operating system module----the author doesn't use it much, basically the plug-ins used are all After encapsulation, give
the simplest little chestnut: node judges whether it is mac or window, and distinguishes the slash and backslash of the path.
15. Buffer and stream--to make file transfer faster and improve file processing performance
16. Typescript--the examples on the official website are all js, don't look at it, learn typescript and then look at
17. WebAssembly--- - barely used, don't look at it

4. Use nodejs to implement vue's devServer

This section involves the implementation of http, file system, hot update (hot update means that the js code is changed, and the browser will automatically refresh), the simple implementation of express (really very simple), the principle of vue proxy (vue uses http-proxy )
directory structure of the code
insert image description here

Not much to say, upload the code, the code is written for others to understand, no amount of nonsense is useless
ps:为了同一个模块集中放一块,代码用了var,按顺序一段段复制成一个文件就能跑起来
1. Start the server (http is used here to correspond to the official website learning, it will be more comfortable to use express, and koa is also possible, but you have to do it yourself plus dependency)

const fs=require('fs');
const http = require('http')
const Url = require('url')
const port = 3000;
const basePath = __dirname;
// 这里返回指的是访问localhost:3000
const server = http.createServer();
// 启动监听
server.listen(port, () => {
    
    
  console.log("启动成功")
})

2. Listening request

server.on('request', (req, res) => {
    
    
    // http接数据很麻烦,还是用express封装好的爽
    let data = '';
    req.on('data', chunk => {
    
    
        data += chunk;
    })
    // 为了代码简单,直接接收完数据在处理
    req.on('end', async () => {
    
    
        // 把数据挂在body上
        req.body = data;
        // vue的代理实现
        if(await getProxy(req, res)){
    
    
            return;
        };
        // 作为前端服务器,返回静态文件
        if(responseFile(req, res)){
    
    
            return;
        }
        // 作为后端服务器,只接收get post
        express.run(req, res);
    })
});

3. Return static files

// 返回文件
var resFile = (res, path, type, contentType) => {
    
    
    let realPath = `${
      
      basePath}/html/${
      
      path}${
      
      type}`
    fs.readFile(realPath, (err, data) => {
    
    
        if (err) {
    
    
            response404(res);
        }
        res.writeHead(200, {
    
    'Content-Type': contentType})
        res.end(data);
    });
}
// demo只支持返回js 跟 index.html
var responseFile = (req, res)=>{
    
    
    const {
    
     path }  = Url.parse( req.url );
    if( !path || path === '/' ){
    
    
        resFile(res, 'index', '.html', 'text/html;charset=UTF-8')
        return true;
    }
    let jsIndex = path.indexOf('.js');
    if(jsIndex > -1){
    
    
        resFile(res, path.substring(0, jsIndex), '.js', 'application/javascript;charset=UTF-8');
        return true;
    }
    return false;
}
// 简单返回404
var response404 = (res) =>{
    
    
    res.writeHead(404, {
    
    'Content-Type': 'text/plain'});
    res.end('404');
}

4. Return get and post requests

// 自制个express,实际上express也就比我多了亿点点细节
var express = {
    
    
    postUrl: {
    
    },
    getUrl: {
    
    },
    run(req,res){
    
    
        // 作为后端服务器返回get,post
        const method = req.method.toLowerCase();
        const {
    
     path }  = Url.parse( req.url );
        // 加多个json返回方法,简化版express.json()
        res.json = (data)=>{
    
    
            res.setHeader('Content-Type', 'text/html;charset=UTF-8');
            res.end(JSON.stringify(data))
        }
        // 判断是get还是post,路径在不在列表里,在列表里就调回调函数
        if(method === 'get' && this.getUrl[path]){
    
    
            this.getUrl[path](req, res);
            return;
        }
        if(method === 'post' && this.postUrl[path]){
    
    
            this.postUrl[path](req, res);
            return;
        }
        // 没有就返回404
        response404(res);
    },
    // get post都只是把callback存起来,
    post(url, callBack){
    
    
        this.postUrl[url] = callBack;
    },
    get(url, callBack){
    
    
        this.getUrl[url] = callBack;
    }
}
// 定义两个接口
express.post('/setData', (req, res)=>{
    
    
    res.json({
    
    code:200, msg:'success'})
})
express.get('/getData', (req, res)=>{
    
    
    res.json({
    
    code:200,data:{
    
    count:1},msg:'success'})
})

5. Simple proxy implementation

// 假如是vue devServer传进来的
var proxyRouter = {
    
    
    '/api': {
    
    
        target: 'http://localhost:3000',
        pathRewrite: path => {
    
    
            return path.replace('/api', '');
        },
    }
}
// 实现代理
var getProxy = (serverReq, serverRes)=>{
    
    
    const url  = Url.parse( serverReq.url );
    const path = url.path;
    // 斜杆是index.html
    if(path === '/'){
    
    
        return;
    }
    // 判断是否在代理列表中
    let currentRoute = '';
    for(let route in proxyRouter){
    
    
        if( path.indexOf(route) === 0 ){
    
    
            currentRoute = route;
            break;
        }
    }
    if(!currentRoute){
    
    
        return false;
    }
    // 解析proxyRouter
    let target = Url.parse( proxyRouter[currentRoute].target );
    // pathRewrite的作用
    let targetPath = proxyRouter[currentRoute].pathRewrite(url.path)
    // 真正的请求地址及配置
    const options = {
    
    
        hostname: target.hostname,
        port: target.port,
        path: targetPath,
        method: serverReq.method,
    };
    // 创建请求到真正的地址
    var request = http.request(options, (res) => {
    
    
        res.setEncoding('utf8');
        let data = '';
        res.on('data', (chunk) => {
    
    
            data += chunk;
        });
     	// 请求完把接收到的数据返回到前端
        res.on('end', () => {
    
    
            serverRes.setHeader('Content-Type', 'text/html;charset=UTF-8');
            serverRes.end(data);
        });
    });
    // 请求数据发送到真正的地址
    request.write(serverReq.body);
    request.end();
    return true;
}

Here is an introduction to the proxy. If you are interested, you can poke the front-end proxy analysis

6. Hot update, using socket.io (recommended by the official website, it must be a high-quality product)

const {
    
     Server } = require("socket.io");
const io = new Server(server);
io.on('connection', (socket) => {
    
    
    console.log('a user connected');
});

// 简单监听文件夹,文件夹
fs.watch('./html', {
    
     encoding: 'utf-8' }, (eventType, filename) => {
    
    
    console.log(filename);
    io.emit('message',123)
});

7. Front-end index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <style>
        #app {
    
     text-align: center; color: #fff; line-height: 400px; width: 400px; height: 400px; border-radius: 200px; background: greenyellow; }
    </style>
</head>
<body>
	<div id="app">生活必须带点绿</div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src=./demo.js></script>
    <script src=./404.js></script>
    <script type="importmap">
        {
    
     "imports": {
    
     "socket.io-client": "https://cdn.socket.io/4.4.1/socket.io.esm.min.js" } }
    </script>
    <script type="module">
        import {
    
     io } from "socket.io-client";
        const socket = io('ws://localhost:3000');
        socket.on('message',function(evt){
    
    
            location.reload();
        })
    </script>
    <script>
        console.log('onload')
    </script>
</body>
</html>

8. Front-end demo.js

// get示例
axios.get('http://localhost:3000/getData').then(function(data){
    
    
    console.log(data)
})
// post示例
axios.post('http://localhost:3000/setData').then(function(data){
    
    
    console.log(data)
})
// 代理示例,代理完访问的还是/setData
axios({
    
    url:'http://localhost:3000/api/setData',method:'post',data: {
    
    value: 1}}).then(function(data){
    
    
    console.log(data)
})

Five, use nodejs to simply implement a vue-cli

The principle of vue-cli is to download a project for you to the local, and then add a lot of instructions and parameters so that you can customize a scaffold you need, and directly upload the code to make a simple version. To run, you need to download the code first, click here
insert image description here

I won’t talk about how to publish the cli here, the space is already very long. Tell me how to run locally.

  1. The r-cli folder executes npm instll to install dependencies
  2. Put the r-cli folder in C:\Users\window login user\AppData\Roaming\npm\node_modules
  3. Put the script file in the shell into C:\Users\window login user\AppData\Roaming\npm
  4. Finally, just find an empty folder and execute r-cli init
  5. Mac is more troublesome and not supported for the time being

ps: Basically, the node plug-ins are used. The code is the cli implemented in the author's original project. After simplification, the comments have been changed again. Let's simply look at the code principle. After all, when you look at the vuecli source code, there are not many comments.

#!/usr/bin/env node
// r是作者名字首字母,没别的意思
process.title = 'r-cli';
// 指令模块,可以生成一个可以在cmd执行的指令
const program = require('commander');
// node总是离不开文件读写
const fs = require('fs');
// 文件读写总是离不开用path
const path = require('path');
// node跟命令窗口交互的插件
const inquirer = require('inquirer');
// 插件作用:在代码中实现在cmd中执行命令的效果
const execa = require('execa');
// chalk是一个node在命令窗口按颜色输出文字的插件
const chalk = require('chalk');
// node在命令窗口显示loading的工具
const ora = require('ora');
const spinner = ora();

// 在cmd中执行 r-cli -v 查看版本
program.version(require('../package').version, '-v, --version')
    .usage('<command> [options]')
// r-cli init  直接开始创建
program
    .command('init')
    .description('init a project in current folder')
    .action(function() {
    
    
        initProjectInCurrentFolder();
    });
// 读取命令参数到program中
program.parse(process.argv);
// 根据项目名name,项目路径path生成项目
async function makeProjectWithProjectConfig({
     
      name, path }) {
    
    
    // 根据类型,名称和路径生成项目
    await makeProject({
    
    
        name,
        path
    });
    // 询问是不是要执行 npm install
    const installAnswers = await inquirer.prompt([{
    
    
        type: 'list',
        name: 'install',
        message: 'install project dependency packages ?',
        choices: [{
    
    
            name: 'yes',
            value: 'yes'
         }, {
    
    
            name: 'no',
            value: 'no'
         }]
    }]);
    // cmd中输入了yes
    if (installAnswers.install === 'yes') {
    
    
        // 执行npm i 
        await execa('npm', ['i', '--prefix', path],{
    
    
            stdio: 'inherit'
        });
    }
    else {
    
    
    	// 返回执行命令的描述
        showMakeProjectResult({
    
    
            name,
            path,
            isInstall: installAnswers.install === 'yes'
        });
        return ;
    }
    // 询问是不是要执行npm run dev
    const startAnswers = await inquirer.prompt([{
    
    
        type: 'list',
        name: 'start',
        message: 'start project now?',
        choices: [{
    
    
            name: 'yes',
            value: 'yes'
         }, {
    
    
            name: 'no',
            value: 'no'
         }]
    }]);

    if (startAnswers.start === 'yes') {
    
    
        await execa('npm', ['run', 'dev', '--prefix', path],{
    
    
            stdio: 'inherit'
        });
        return ;
    }
    else {
    
    
    	// 返回执行命令的描述
        showMakeProjectResult({
    
    
            name,
            path,
            isInstall: installAnswers.install === 'yes'
        })
    }
    
}
// 返回执行命令的描述
function showMakeProjectResult({
     
     
    name,
    path,
    isInstall
}) {
    
    
    console.log(chalk.green(`
        Success! Created ${
      
      name} at ${
      
      path}.
        We suggest that you begin by typing:
        cd ${
      
      path}
        ${
      
      isInstall ? '': 'npm install'}
        npm run dev
        Happy developing!`
    ));
}
// 获取文件夹名后开始创建项目
async function initProjectInCurrentFolder() {
    
    
    // 获取当前文件夹的名称作为项目名称
    let pathArr = process.cwd().split(/\\|\//);
    let projectName = pathArr.pop();
    makeProjectWithProjectConfig({
    
    
        name: projectName,
        path: process.cwd()
    });
}
// 根据输入的参数,生成对应的项目
async function makeProject(projectArgs) {
    
    
    const {
    
     path } = projectArgs;
    // path 为clone 代码后,项目所在的目录
    await downloadTemplate(path);
    await resetProjectWithArgs(projectArgs);
}
// 更改packagejson的内容
async function resetProjectWithArgs(projectArgs) {
    
    
    // 更改package.json的name
    const packageJsonFilePath = path.resolve(projectArgs.path, 'package.json');
    const packageJson = JSON.parse(fs.readFileSync(packageJsonFilePath));
    packageJson.name = projectArgs.name;
    fs.writeFileSync(packageJsonFilePath, JSON.stringify(packageJson, null, '    '));
}
// 执行git clone下载项目
function downloadTemplate(path) {
    
    
    const successSymbol = chalk.green('✔');
    const failSymbol = chalk.red('x');
    return new Promise( resolve => {
    
    
        spinner.text = `start to clone vue project template from https://gitee.com/liaofeiyu`;
        spinner.start();
        // 这里是使用git下载,所以得先安装有git
        execa('git', ['clone', 'https://gitee.com/liaofeiyu/node-study.git', path]).then(async () => {
    
    
            spinner.stopAndPersist({
    
    
                symbol: successSymbol,
                text: `clone vue project template successfully`
            });
            resolve();
        }).catch( error => {
    
    
            if (error.failed) {
    
    
                spinner.stopAndPersist({
    
    
                    symbol: failSymbol,
                    text: chalk.red(error.stderr)
                });
            }
        });
    });
}

Summarize

Through a few practical examples, you may have found out. Except for the file system (fs, path), we rarely use the basic functions provided by node.js directly, just like we rarely use native js to develop projects directly. For example, express is used for http, socket.io is used for websocket, inquirer is used for command line interaction, chalk is used for console to look better, commander is used for interaction with command window instructions, and so on.
The ecology is endless, and some tools are always created. The more you know, the more you feel that you lack knowledge.
However, there are always some constants, that is js, no matter what plug-in is used, the writing of code logic is based on js. Learn js well, give full play to your initiative and creativity, and you will be the next vue author and react author.

ps: The author tries to keep the code as simple as possible. In the actual project, a lot of details need to be added, such as using ts or doing some type judgment, using try catch to print error logs, etc. In the process of writing, I often write more and more, and write more and more. In the end, I still wrote so much after deleting, deleting, modifying and modifying.

pps: If you think this article is helpful to you, please give me a thumbs up to let the author know that what he wrote still has a little value. If there is anything wrong with the writing, please leave a message to correct me.

Guess you like

Origin blog.csdn.net/qq_38217940/article/details/123736492
Recommended