nodejs desde el combate real hasta la entrada

prefacio

Muchas personas aprenden node.js, pero todavía tienen un conocimiento a medias después de aprenderlo. Sienten que lo han aprendido pero no lo han aprendido completamente. Cuando quieren usarlo en un proyecto, todavía tienen la sensación de estar incapaz de comenzar. Este artículo explica principalmente la aplicación de node.js en proyectos reales para principiantes a través de varios ejemplos prácticos y utiliza un código tan simple como sea posible para hacer algo primero para mejorar la confianza de los principiantes en el aprendizaje. Si desea estudiar en profundidad, aún debe concentrarse en el sitio web oficial, y también puede encontrar algunos libros para ayudar, como "nodo. etc., y luego incursionar en varios proyectos.

Este artículo no habla sobre conocimientos básicos, sino que se centra en el combate real. Para los estudiantes que no han aprendido node.js, pueden pasar media hora o una hora navegando por el tutorial introductorio en el sitio web oficial (la tercera sección de este artículo tiene una pequeña sugerencia). ¿Qué tiene de malo este artículo? El lugar, bienvenido a corregirme.

Toda la dirección de git del código en este artículo: https://gitee.com/liaofeiyu/node-study, copie o pinche aquí

1. ¿Qué puede hacer nodejs?

¿Qué es nodejs? El sitio web oficial dice esto: Node.js es un entorno de tiempo de ejecución de JavaScript de código abierto y multiplataforma . En otras palabras, nodejs es solo un entorno para ejecutar JavaScript, que proporciona algunos métodos internos. Lo que puede hacer depende completamente del usuario.

A menudo usamos nodejs para hacer las siguientes cosas:

  1. Como servidor back-end,
    esto no se menciona, ya sea el sitio web oficial o un libro, se trata de esto. Pero hay muchos talentos de back-end baratos, ¿por qué gastar tanto dinero para encontrar un experto en node.js? Es más, pocas operaciones y mantenimiento entienden nodo, tienes que enseñar despliegue de operación y mantenimiento, y si vas demasiado lejos, tienes que escribir docker tú mismo (la dolorosa experiencia del blogger), o salir temprano del trabajo para jugar con tu novia ( cabeza de perro).
  2. Utilizado como middleware.
    Debido a que js es mucho más conveniente para procesar datos json que otros lenguajes de back-end (como java), algunas empresas agregarán un servicio de nodo entre el back-end y el front-end para el procesamiento de datos y devolverán el más cómodo. Formato de datos para el front-end para usar. Deje que los extremos delantero y trasero funcionen más felizmente. Sin embargo, hay un intermediario adicional para marcar la diferencia de precio, y el costo aumentará de inmediato, por lo que las empresas ordinarias no tienen esta capa.
  3. Como una herramienta de construcción front-end, como un paquete web
  4. Herramientas de eficiencia hechas a sí mismas
    Por ejemplo, si obtiene un Excel, debe convertirlo en json y colocarlo en un archivo estático local. Es posible que no encuentre una herramienta adecuada en Internet, por lo que también es muy bueno escribir un herramienta node.js para procesarlo (no digas python, js es el mejor lenguaje).

2. Usa nodejs para crear herramientas de eficiencia personal

Después de leer tanto texto, relajémonos escribiendo algo de código primero.

proceso excel


Es más conveniente para el procesamiento de nodos de Excel usar node-xlsx para analizar.Usar nodemon puede evitar que reinstale el nodo xx.js cada vez que cambie js

npm install node-xlsx
npm install nodemon -g

El ejemplo es relativamente simple, simplemente pegue el código directamente

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();

Procese datos de Excel y conviértalos en 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);

Devolver datos simulados como un servidor simulado

Recomiendo descaradamente mi primer blog: varios esquemas de uso de datos de simulación frontal

inserte la descripción de la imagen aquí

3. Tutorial introductorio en el sitio web oficial del nodo

注意:仅限于第一次浏览需要关注的点,有学过基础的就跳过吧
1. Ejecute y salga
del nodo xx, js ejecute
ctrl+c para salir,
use processs.exit(0) para salir en el
código 2, los parámetros están relacionados, solo recuerde el siguiente código

// 读取环境变量
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, consola

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

4. Reciba la entrada de la línea de comandos----vue-cli hablará sobre ello.
5. REPL ---- ingrese el nodo en la línea de comando, y luego puede escribir js en la herramienta de comando, la mayoría de las personas no hacen
esto
7. pacakge.json: elementos de configuración que deben observarse cuidadosamente
. Bucle de eventos: si no lo comprende, no afectará su uso del nodo. Si no lo comprende lo suficientemente bien, es inútil. Aprenda a lidiar con las entrevistas primero, aprenda lentamente y comprenderá más tarde.
process.nextTick(), setImmediate() también se puede entender primero.
El poco conocimiento introducido: en temporizadores y promesas, los errores no gramaticales no afectarán la ejecución de su otro código, intente usar try catch en node.
10. Temporizador, promesa, asíncrono, espera: esto es lo que debe saber
sobre
js: para construir un servidor, veamos el combate real directamente
13. Sistema de archivos: el documento api es demasiado largo, voltee directamente el documento en combate real
14. Módulo del sistema operativo----el autor no lo usa mucho, básicamente los complementos usados ​​son todos Después de la encapsulación, dé
la pequeña castaña más simple: el nodo juzga si es mac o ventana, y distingue la barra oblicua y la barra invertida de la ruta.
15. Búfer y transmisión: para acelerar la transferencia de archivos y mejorar el rendimiento del procesamiento de archivos
16. Mecanografiado: los ejemplos en el sitio web oficial son todos js, no los mire, aprenda mecanografiado y luego mire
17. WebAssembly : - - apenas usado, no lo mires

4. Use nodejs para implementar devServer de vue

Esta sección involucra la implementación de http, sistema de archivos, actualización en caliente (actualización en caliente significa que el código js se cambia y el navegador se actualizará automáticamente), la implementación simple de express (realmente muy simple), el principio de vue proxy (vue utiliza http-proxy)
estructura de directorios del código
inserte la descripción de la imagen aquí

No hay mucho que decir, cargue el código, el código está escrito para que otros lo entiendan, ninguna cantidad de tonterías es inútil
ps:为了同一个模块集中放一块,代码用了var,按顺序一段段复制成一个文件就能跑起来
1. Inicie el servidor (aquí se usa http para corresponder con el aprendizaje del sitio web oficial, será más cómodo usar express , y koa también es posible, pero tienes que hacerlo tú mismo más dependencia)

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. Solicitud de escucha

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. Devolver archivos estáticos

// 返回文件
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. Devolver solicitudes get y post

// 自制个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. Implementación de proxy simple

// 假如是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;
}

Aquí hay una introducción al proxy. Si está interesado, puede pinchar el análisis del proxy front-end

6. Actualización en caliente, usando socket.io (recomendado por el sitio web oficial, debe ser un producto de alta calidad)

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. Índice frontal.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. Demostración frontal.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)
})

Cinco, use nodejs para simplemente implementar un vue-cli

El principio de vue-cli es descargar un proyecto para usted en el local y luego agregar muchas instrucciones y parámetros para que pueda personalizar el andamio que necesita y cargar directamente el código para hacer una versión simple. Para ejecutar, primero debe descargar el código, haga clic aquí
inserte la descripción de la imagen aquí

No hablaré de cómo publicar el cli aquí, el espacio ya es muy largo. Dime cómo ejecutar localmente.

  1. La carpeta r-cli ejecuta npm instll para instalar dependencias
  2. Coloque la carpeta r-cli en C:\Users\window login user\AppData\Roaming\npm\node_modules
  3. Coloque el archivo de script en el shell en C:\Users\window login user\AppData\Roaming\npm
  4. Finalmente, busque una carpeta vacía y ejecute r-cli init
  5. Mac es más problemático y no es compatible por el momento

pd: Básicamente, se utilizan los complementos de nodo. El código es el cli implementado en el proyecto original del autor. Después de la simplificación, los comentarios se han cambiado nuevamente. Simplemente veamos el principio del código. Después de todo, cuando miras el código fuente de vuecli, no hay muchos comentarios.

#!/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)
                });
            }
        });
    });
}

Resumir

A través de algunos ejemplos prácticos, es posible que lo haya descubierto. Excepto por el sistema de archivos (fs, ruta), rara vez usamos las funciones básicas proporcionadas por node.js directamente, al igual que rara vez usamos js nativo para desarrollar proyectos directamente. Por ejemplo, express se usa para http, socket.io se usa para websocket, inquirer se usa para la interacción de la línea de comandos, chalk se usa para que la consola se vea mejor, comandante se usa para la interacción con las instrucciones de la ventana de comandos, etc.
La ecología es infinita y siempre se crean algunas herramientas, cuanto más sabes, más sientes que te falta conocimiento.
Sin embargo, siempre hay algunas constantes, es decir, js, no importa qué complemento se use, la escritura de la lógica del código se basa en js. Aprende js bien, dale rienda suelta a tu iniciativa y creatividad, y serás el próximo autor de vue y de reacción.

pd: El autor trata de mantener el código lo más simple posible. En el proyecto real, se deben agregar muchos detalles, como usar ts o hacer algún tipo de juicio, usar try catch para imprimir registros de errores, etc. En el proceso de escritura, a menudo escribo más y más, y escribo más y más. Al final, todavía escribí mucho después de borrar, borrar, modificar y modificar.

pps: si cree que este artículo es útil para usted, déme un pulgar hacia arriba para que el autor sepa que lo que escribió todavía tiene un poco de valor. Si hay algún problema con la escritura, por favor deje un mensaje para corregirme.

Supongo que te gusta

Origin blog.csdn.net/qq_38217940/article/details/123736492
Recomendado
Clasificación