最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Express服務(wù)器端代碼熱加載的實(shí)現(xiàn)代碼

 更新時間:2024年01月29日 08:27:35   作者:forhot2000  
這篇文章主要介紹了Express服務(wù)器端代碼熱加載的實(shí)現(xiàn),文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

創(chuàng)建項(xiàng)目

首先,創(chuàng)建一個 express 的創(chuàng)建項(xiàng)目

mkdir your-project
cd your-project
npm init -y
npm install --save express

添加 src/main.js

// ./src/main.js
const express = require('express');

function bootstrap() {
  const app = express();

  app.all('*', (req, res) => {
    res.send(`hello, world!\n`);
  });

  app.listen(3000, function () {
    console.log('listen on http://localhost:3000');
  });
}

bootstrap();

修改 package.json,增加 start 命令

{
  ...
  "scripts": {
    "start": "node src/main.js"
  },
  ...
}

啟動服務(wù)

npm run start

OK,這就啟動了一個基本的 express app 了。

但是,每次修改代碼后,都需要手動重新啟動服務(wù),對于開發(fā)來說,這是個非常煩人的工作,下面讓我們一步一步來優(yōu)化它。

使用 nodemon 自動重啟

使用 nodemon 檢測文件變動,重啟服務(wù),這種方式很簡單,不需要修改現(xiàn)有代碼。

安裝 nodemon

npm install --save-dev nodemon

修改 package.json,增加 dev 命令,使用 nodemon 啟動,其它都不用改

{
  ...
  "scripts": {
    "dev": "nodemon src/main.js",
    "start": "node src/main.js"
  }
  ...
}

配置好后,使用 npm run dev 啟動服務(wù),nodemon 會檢測文件改動自動重啟服務(wù)器,這樣你不用再頻繁的重啟服務(wù),歡快地去寫代碼了。

如果你需要排除一些文件的監(jiān)控,比如僅檢測 src 目錄下的 js 文件,并忽略測試代碼,可以添加 nodemon 的配置文件 nodemon.json

{
  "watch": ["src/"],
  "ext": "js",
  "ignore": ["*.test.js", "*.spec.js"]
}

如上所示,nodemon 的使用非常簡單,配合 ts-node 它還能支持 typescript,已經(jīng)能滿足大多數(shù)用戶的使用場景了。

不過,當(dāng)項(xiàng)目變的越來越大,每次改動一個地方就重新啟動服務(wù)就變得有點(diǎn)麻煩了。

使用 webpack HMR 實(shí)現(xiàn)模塊熱加載

webpack 的 HMR 功能會通知到哪些文件發(fā)生了變化需要重新加載,這個功能被廣泛用在前端開發(fā)框架中,修改代碼后立即刷新頁面,其實(shí)它也還可以被用在服務(wù)器端代碼的加載過程中,讓我們來看看如何實(shí)現(xiàn)。

首先,添加依賴包

npm install --save-dev webpack webpack-cli webpack-node-externals run-script-webpack-plugin rimraf

添加兩個新文件,用來測試熱加載

// ./src/count.js
let n = 0;

export function inc() {
  n++;
  return n;
}
// ./src/hello.js
export function greet(name = 'World') {
  return `Hello, ${name}!`;
}

修改 src/main.js,引入上面的文件,并添加響應(yīng)熱加載的代碼,由于使用了 webpack,現(xiàn)在可以在代碼中使用 ES6 的 import 了,改動后的 main.js 代碼如下:

// ./src/main.js
import express from 'express';
import { createServer } from 'http';
import { inc } from './count';
import { greet } from './hello';

function bootstrap() {
  const app = express();

  // 默認(rèn)情況下 express 會自動創(chuàng)建 server,這里手動創(chuàng)建 server 
  // 是為了在后面調(diào)用 server.close() 關(guān)閉舊的服務(wù)
  const server = createServer(app);

  app.all('*', (req, res) => {
    const n = inc();
    res.send(`${n}: ${greet('bob')}\n`);
  });

  server.listen(3000, function () {
    console.log('listen on http://localhost:3000');
  });

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => server.close());
  }
}

bootstrap();

修改 package.json

{
  ...
  "scripts": {
    "dev": "rimraf dist && webpack --config webpack-hmr.config.js --watch",
    "build": "rimraf dist && webpack --config webpack.config.js",
    "start": "node dist/server.js"
  },
  ...
}

添加 build 的 webpack 配置文件 webpack.config.js

// ./webpack.config.js
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  mode: 'production',
  entry: ['./src/main.js'],
  target: 'node',
  externals: [nodeExternals()],
  resolve: {
    extensions: ['.js'],
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'server.js',
  },
};

添加 dev 的 webpack 配置文件 webpack-hmr.config.js

// ./webpack-hmr.config.js
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: ['webpack/hot/poll?100', './src/main.js'],
  target: 'node',
  externals: [
    nodeExternals({
      allowlist: ['webpack/hot/poll?100'],
    }),
  ],
  resolve: {
    extensions: ['.js'],
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new RunScriptWebpackPlugin({ name: 'server.js', autoRestart: false }),
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'server.js',
  },
};

開發(fā)模式下,我們使用 npm run dev 啟動服務(wù),啟用熱加載功能。

接下來,我們來測試一下熱加載

curl http://localhost:3000/

輸出

1: Hello, boy!

當(dāng)我們修改 main.js 后,服務(wù)器端僅需要重新編譯并加載 main.js 一個文件

...
asset server.js 46.1 KiB [emitted] (name: main)
asset main.44ac5c7bc9372be2efa5.hot-update.js 2.58 KiB [emitted] [immutable] [hmr] (name: main)
asset main.44ac5c7bc9372be2efa5.hot-update.json 28 bytes [emitted] [immutable] [hmr]
Entrypoint main 48.7 KiB = server.js 46.1 KiB main.44ac5c7bc9372be2efa5.hot-update.js 2.58 KiB
runtime modules 23.5 KiB 9 modules
cached modules 4.69 KiB [cached] 7 modules
./src/main.js 677 bytes [built] [code generated]
webpack 5.89.0 compiled successfully in 32 ms
[HMR] Updated modules:
[HMR]  - ./src/main.js
[HMR] Update applied.
listen on http://localhost:3000/

再次訪問服務(wù)

curl http://localhost:3000/

輸出

2: Hello, boy!

我們可以看到,count.js 中的計(jì)數(shù)并沒有重置

再試下修改 hello.js,webpack 會重新編譯并加載 hello.js,因?yàn)?nbsp;main.js 引用了 hello.js,所以雖然不會重新編譯 main.js,但是它也會被重新加載。

...
asset server.js 46.1 KiB [emitted] (name: main)
asset main.56dcdc90891aac75fe1c.hot-update.js 1.37 KiB [emitted] [immutable] [hmr] (name: main)
asset main.56dcdc90891aac75fe1c.hot-update.json 28 bytes [emitted] [immutable] [hmr]
Entrypoint main 47.5 KiB = server.js 46.1 KiB main.56dcdc90891aac75fe1c.hot-update.js 1.37 KiB
runtime modules 23.5 KiB 9 modules
cached modules 5.28 KiB [cached] 7 modules
./src/hello.js 72 bytes [built] [code generated]
webpack 5.89.0 compiled successfully in 65 ms
[HMR] Updated modules:
[HMR]  - ./src/hello.js
[HMR]  - ./src/main.js
[HMR] Update applied.
listen on http://localhost:3000/

再次訪問服務(wù)

curl http://localhost:3000/

輸出

3: Hello, boy!

可以看到,count.js 中的計(jì)數(shù)任然沒有被重置,說明只要不修改 count.js 及其依賴項(xiàng),count.js 就不會被重新加載。

發(fā)布到生產(chǎn)環(huán)境

生產(chǎn)環(huán)境下,我們不需要熱加載功能,那么我們可以運(yùn)行 npm run build 構(gòu)建代碼,然后再運(yùn)行 npm start,使用構(gòu)建后的代碼啟動服務(wù),這樣優(yōu)先保證線上環(huán)境的性能。

動態(tài)加載目錄的問題

另外還有一個常見的問題,有時候我們需要動態(tài)的加載某個目錄下的所有文件,這個可以用 await import 來加載模塊來完成。

讓我們來改一下 main.js,將 bootstrap 改成 async 方法,再增加一個 loadControllers 方法

// ./src/main.js
// ...
import { readdir } from 'fs/promises';
import { resolve } from 'path';

async function bootstrap() {
  // ...
  const server = createServer(app);

  // 動態(tài)加載 controllers 目錄下的所有文件
  await loadControllers(app);

  app.all('*', (req, res) => { /* ... */ });
  //...
}

async function loadControllers(app) {
  try {
    // 注意,這里應(yīng)該是掃描 src 目錄,而不是 dist 目錄
    const files = await readdir(resolve('./src/controllers'));
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const name = file.substring(0, file.length - 3); // remove ext '.js'
      const module = await import('./controllers/' + name);
      app.use(`/${name}`, module.default);
    }
  } catch (err) {
    console.error(err);
  }
}

bootstrap();

提示

遍歷目錄文件的時候需要使用源文件的目錄,而不能使用文件的相對目錄

錯誤的代碼

// 編譯后的代碼會提示找不到目錄 ./dist/controllers 
readdir(path.join(__dirname, 'controllers')); 

正確的代碼

readdir(path.resolve('./src/controllers'));

再添加一個 controller 文件 src/controllers/posts.js

// ./src/controllers/posts.js
import { Router } from 'express';

const router = Router();

router.get('/', (req, res) => {
  res.send([
    {
      id: 1,
      title: 'post 1',
      content: 'content of the post',
    },
  ]);
});

export default router;

測試下新加的 controller

curl http://localhost:3000/posts

輸出

[{"id":1,"title":"post 1","content":"content of the post"}]

這種方式存在一個問題,每次都要去掃描 src 目錄,導(dǎo)致部署的時候還需要將 src 目錄復(fù)制到服務(wù)器,而這些 src 目錄下的文件除了提供一個 filename 就沒有其它作用了,我認(rèn)為這不是一個好的代碼。

如果要避免這種隱式的動態(tài)加載,可以將它改成如下代碼:

// 顯示聲明有哪些 controllers
const controllerNames = [
  'posts',
];

async function loadControllers(app) {
  const controllers = controllerNames.map((name) => ({ name }));
  for (let i = 0; i < controllers.length; i++) {
    const controller = controllers[i];
    try {
      const module = await import(`./controllers/${controller.name}`);
      controller.router = module.default;
    } catch (err) {
      // console.error(err);
    }
  }

  controllers.forEach(({ name, router }) => {
    if (router) {
      const path = `/${name}`;
      app.use(path, router);
      console.log(`mount controller '${name}' on '${path}'`);
    } else {
      console.error(`cannot find controller '${name}'`);
    }
  });
}

以上就是Express服務(wù)器端代碼熱加載的實(shí)現(xiàn)代碼的詳細(xì)內(nèi)容,更多關(guān)于Express代碼熱加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入理解Node module模塊

    深入理解Node module模塊

    這篇文章主要介紹了深入理解Node module模塊,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Nodejs 模塊化實(shí)現(xiàn)示例深入探究

    Nodejs 模塊化實(shí)現(xiàn)示例深入探究

    這篇文章主要為大家介紹了Nodejs 模塊化實(shí)現(xiàn)示例深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • node.js+npm的環(huán)境配置以及添加鏡像(保姆級教程)

    node.js+npm的環(huán)境配置以及添加鏡像(保姆級教程)

    本文主要介紹了node.js+npm的環(huán)境配置以及添加鏡像,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • node.js中的fs.ftruncate方法使用說明

    node.js中的fs.ftruncate方法使用說明

    這篇文章主要介紹了node.js中的fs.ftruncate方法使用說明,本文介紹了fs.ftruncate的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node.js中cluster的使用教程

    node.js中cluster的使用教程

    這篇文章主要介紹了node.js中cluster的使用教程,分別介紹使用NODE中cluster利用多核CPU、通過消息傳遞來監(jiān)控工作進(jìn)程狀態(tài)以及終止進(jìn)程等功能,給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來一起看看吧
    2017-06-06
  • 解決nodejs的npm命令無反應(yīng)的問題

    解決nodejs的npm命令無反應(yīng)的問題

    今天小編就為大家分享一篇解決nodejs的npm命令無反應(yīng)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • nodejs如何將多個目錄文件合并成一個

    nodejs如何將多個目錄文件合并成一個

    這篇文章主要介紹了nodejs如何將多個目錄文件合并成一個問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • node.js中fs.stat與fs.fstat的區(qū)別詳解

    node.js中fs.stat與fs.fstat的區(qū)別詳解

    fs.stat和fs.fstat他們都是用來獲取文件的狀態(tài)信息,下面這篇文章主要給大家介紹了關(guān)于node.js中fs.stat與fs.fstat區(qū)別的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • 用nodejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動態(tài))

    用nodejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動態(tài))

    下面小編就為大家?guī)硪黄胣odejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動態(tài))。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • WebSocket實(shí)現(xiàn)簡單客服聊天系統(tǒng)

    WebSocket實(shí)現(xiàn)簡單客服聊天系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了WebSocket實(shí)現(xiàn)簡單客服聊天系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評論

崇义县| 昭觉县| 三都| 遂川县| 沂源县| 庆阳市| 东兴市| 家居| 漳浦县| 昆明市| 陆良县| 井陉县| 芜湖县| 鸡西市| 黑水县| 石城县| 乃东县| 乡城县| 时尚| 烟台市| 柳河县| 龙南县| 藁城市| 浙江省| 金寨县| 刚察县| 澜沧| 石柱| 夏津县| 板桥市| 洪雅县| 东丰县| 德阳市| 彰化市| 定西市| 沂源县| 铁力市| 富裕县| 娱乐| 二连浩特市| 朝阳区|