使用 webpack 构建 node 开发环境

在我们日常开发node项目的时候,通常是直接使用node命令来运行我们的项目,例如我就会使用nodemon来创建开发环境来运行我的项目,在开发完成之后我会使用一些构建工具来构建我的项目,例如webpackrollup等等;

当然这并不重要,关键在于打包完成了之后可能会出现一些问题,就是开发环境和生产环境的产物不一样,导致项目无法正常运行,例如我们使用fs模块来读取文件,但是在打包之后我们的文件路径就会发生变化,这就导致了我们的项目无法正常运行;

同时我们也可能会使用一些新的语法,例如es6es7等等,如果我们的生产环境下的node版本不支持这些语法,那么我们的项目也会无法正常运行,这个时候我们就需要使用babel来进行转码;

所以为了解决这些问题,我们需要一个开发环境和生产环境一致的环境,例如我现在使用的是webpack来构建我的项目,那么我同样使用webpack来构建一个开发环境,这样就可以保证我们的开发环境和生产环境一致;

接下来我们就来看看如何使用webpack来构建一个node的开发环境,如果你还不了解webpack,可以先看看webpack的一些基本概念;

1. 初始化项目

首先我们需要初始化一个node项目,这里我使用npm来初始化一个项目,当然你也可以使用yarn来初始化一个项目;

bash 复制代码
npm init -y

然后我们安装一些依赖,例如我使用的是express来创建一个简单的node服务,当然你也可以使用其他的一些框架,例如koahapi等等;

bash 复制代码
npm install express

写一个简单的node服务,例如我写一个简单的express服务;

javascript 复制代码
const express = require('express');

const app = express();

app.get('/', (req, res) => {
    res.send('Hello World!');
})

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

然后我们使用node命令来运行我们的项目,例如我使用nodemon来运行我的项目;

bash 复制代码
nodemon index.js

注意:nodemon是需要单独安装的,你可以使用npm install nodemon -g来全局安装,也可以使用npm install nodemon --save-dev来安装到项目中;

不出意外的情况下,我们的项目应该可以正常运行,现在在浏览器中输入http://localhost:3000,我们应该可以看到Hello World!

现在可以随便修改一些东西,例如我修改一下Hello World!!!,然后我们可以看到我们的项目会自动刷新,接着刷新页面,我们就可以看到我们的修改已经生效了;

目录结构如下:

2. 使用 webpack 构建开发环境

使用webpack来构建我们的开发环境,首先我们需要安装一些依赖:webpackwebpack-cli这两个

bash 复制代码
npm install webpack webpack-cli --save-dev

然后我们需要创建一个webpack的配置文件,例如我创建一个webpack.config.js文件;

javascript 复制代码
const path = require("node:path");

module.exports = {
  target: "node", // 指定构建的目标是node
  mode: "development", // 指定构建的模式是开发模式
  entry: {
      index: "./index.js", // 指定入口文件
  },
  output: {
    path: path.resolve(__dirname, "./dist"), // 指定输出的目录
    filename: '[name].js', // 指定输出的文件名
    clean: true, // 每次构建之前清空输出目录
  },
  devtool: "source-map", // 生成source-map
}

这样我们就完成了一个简单的webpack配置,然后我们可以使用webpack命令来构建我们的项目;

bash 复制代码
npx webpack

不出意外我们可以看到根目录下多了一个dist目录,然后我们可以看到里面有一个index.js文件,这个文件就是我们构建之后的文件;

现在我们可以使用node命令来运行我们的项目,例如我直接使用node来运行我们的项目;

bash 复制代码
node dist/index.js

这其实就是生产环境下的产物文件,我们可以看到生成的文件体积非常大,这是因为webpack默认会将所有的node_modules都打包进去,这样就导致了我们的文件体积非常大;

但是在开发环境下我们并不需要这些东西,因为这样会影响我们的开发效率,所以我们需要使用webpack-node-externals来排除这些东西;

2.1 使用 webpack-node-externals

首先我们需要安装webpack-node-externals这个依赖;

bash 复制代码
npm install webpack-node-externals --save-dev

然后我们需要修改一下我们的webpack配置文件;

javascript 复制代码
const path = require("node:path");
const nodeExternals = require("webpack-node-externals");

module.exports = {
    // ...其他配置
  externals: nodeExternals(),
}

非常简单就可以完成了,然后我们再次使用webpack命令来构建我们的项目;

bash 复制代码
npx webpack
  • 没有排除node_modules之前的文件体积

  • 排除node_modules之后的文件体积

可以看看对比之后的文件体积,我们可以看到排除node_modules之后的文件体积小了很多,这样就可以提高我们的开发效率;

2.2 结合 nodemon 来构建开发环境

直到现在我们都需要单独构建项目,然后重新运行我们的项目,这样会非常麻烦,所以我们需要结合nodemon来构建我们的开发环境;

首先我们需要解决webpack每次发生文件修改之后都需要重新构建的问题,这个时候我们可以使用webpack --watch来监听文件的变化,然后自动构建我们的项目;

bash 复制代码
npx webpack --watch

当然我们完全可以将这个指令写到package.jsonscripts中,例如我写一个dev:build指令;

json 复制代码
{
  "scripts": {
    "dev:build": "webpack --watch"
  }
}

这里指令就是单独用来构建开发环境的,然后我们可以使用nodemon来运行我们的项目,我再写一个dev:start指令;

json 复制代码
{
  "scripts": {
    "dev:build": "webpack --watch",
    "dev:start": "nodemon dist/index.js"
  }
}

接下来我们将这两个指令组合起来,我们再写一个dev指令;

json 复制代码
{
  "scripts": {
    "dev:build": "webpack --watch",
    "dev:start": "nodemon ./dist/index.js --watch ./dist/index.js",
    "dev": "npm run dev:build | npm run dev:start"
  }
}

这里使用|来连接两个指令,因为这两个指令本身就是互不干扰的,我们使用|来让这两个指令并行运行即可;

这样当webpack检测到文件发生变化之后就会自动构建我们的项目,然后构建完成之后,nodemon也会检测到文件发生变化,然后自动重启我们的项目,这样就可以保证我们的开发环境和生产环境一致了;

这里有一个细节,就是nodemon只需要监听dist目录下的文件即可,在我这个案例中,我们只需要指定./dist/index.js即可;

现在我们可以体验一下开发环境了,我们先执行npm run dev指令,然后我们可以修改一下我们的index.js文件,来看看效果吧;

2.3 自定义自己的开发环境

既然我们都用上webpack,那么webpack的特性我们都可以使用的,例如我们可以上代码检查、babel转码、别名等等;

当然这些现在网上都有很多的教程,这里我就不再赘述了,我们就简简单单的配置一个别名来体验一下;

我们可以直接在webpack配置文件中配置别名,例如我配置一个@别名;

javascript 复制代码
const path = require("node:path");

module.exports = {
  // ...其他配置
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
    },
  },
}

然后我们可以在index.js中使用这个别名,例如我引入一个utils文件;

javascript 复制代码
import utils from "@/utils";

console.log(utils);

当然我们需要新建这个目录和文件,例如我新建一个src/utils.js文件;

javascript 复制代码
export default "Hello World!";

这里我们使用了es6import/export语法,在node环境如果要使用这个特性,需要在package.json中配置type字段为module

但是我们使用了webpack来构建我们的项目,所以我们并不需要这个配置,webpack会自动帮我们处理这个问题;

注:webpack默认会将es6import/export语法转换为commonjsrequire/module.exports语法;

2.4 调试 node 代码

在开发环境下我们经常需要调试我们的代码,例如我们需要打断点,查看变量的值等等;

而我们将原始代码构建之后,就会变得非常难以调试,这个时候我们可以使用source-map来解决这个问题;

webpack默认会生成source-map,我们只需要在webpack配置文件中配置devtool字段即可;

javascript 复制代码
module.exports = {
  // ...其他配置
  devtool: "source-map",
}

这个在上面的配置文件中已经配置了,这里强调一下;

然后我们还需要在node环境中配置--inspect参数,我们修改一下dev:start指令;

json 复制代码
{
  "scripts": {
    "dev:build": "webpack --watch",
    "dev:start": "cross-env NODE_OPTIONS=--enable-source-maps nodemon --inspect ./dist/index.js --watch ./dist/index.js",
    "dev": "npm run dev:build | npm run dev:start"
  }
}

这里出现了两个新的东西,一个是cross-env,一个是--inspect参数,我们一个一个来看;

  • cross-env:这个是一个跨平台的环境变量设置工具,我们可以使用这个工具来设置环境变量,这样就可以在windowslinux上都能正常运行;
  • --inspect:这个是node的一个调试参数,我们可以使用这个参数来开启node的调试模式,这样我们就可以在chrome浏览器中调试我们的node代码了;

cross-env需要单独安装,你可以使用npm install cross-env --save-dev来安装;

因为我们需要使用source-map,而在node中是需要开启--enable-source-maps参数的,这样我们才能正常的使用source-map,因为环境的问题,我们需要使用cross-env来设置环境变量;

而如果需要代码能调试就需要使用--inspect参数,这样我们就可以调试我们的node代码了;

使用 chrome 调试 node 代码

首先我们需要在chrome浏览器中输入chrome://inspect,然后我们可以看到一个Devices的面板,如下:

因为我们没有携带任何参数,所以是默认的localhost:9229,然后我们点击inspect,然后我们就可以看到一个chrome的调试面板了;

我们可以直接点击Open dedicated DevTools for Node,然后我们就可以看到一个chrome的调试面板了,由于连接需要时间,所以可能会有一些延迟,稍微等待一下即可;

接下来的环节就是我们非常熟悉的调试环节了,我们可以打断点,查看变量的值等等;

使用 webstorm 调试 node 代码

如果你使用的是webstorm,那么你可以直接使用webstorm来调试我们的node代码,这样就会非常方便了;

新版的webstorm直接点击右上角的当前文件,然后选择编辑配置,就会弹出一个配置面板,如下:

然后我们可以点击+,然后选择附加到 Node.js/Chrome,然后我们就可以看到一个配置面板了,如下:

这些都是默认配置,你可以修改一下名称方便自己区分,其他的不需要修改,接下来也是一样的正常调试即可;

个人习惯使用webstorm,所以不太了解vscode是怎么调试node代码的,但是应该是差不多的,可以自行搜索一下;

3. 合并开发环境和生产环境

现在我们已经完成了一个开发环境,但是其实生产环境和开发环境大差不差的,由于node代码是纯粹的js代码,我们并不需要像web一样有非常多的配置;

我们可以非常轻易的将开发环境和生产环境合并在一起,我这里直接使用webpackmode字段来进行区分;

javascript 复制代码
const path = require("node:path");
const nodeExternals = require("webpack-node-externals");

// 使用一个变量来判断当前环境是否是开发环境
const hasDev = process.env.NODE_ENV === "development";

module.exports = {
    resolve: {
        alias: {
            "@": path.resolve(__dirname, "src"),
        },
    },
    target: "node",
    mode: process.env.NODE_ENV || "development", // webpack的 mode 字段,该字段会确认构建的模式,已确认是否开启一些优化
    entry: {
        index: "./index.js"
    },
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: '[name].js',
        clean: true
    },
    stats: hasDev ? "errors-only" : "normal", // 控制台输出的信息,在开发环境下只输出错误信息
    devtool: hasDev ? "inline-source-map" : "source-map", // 开发环境下使用 inline-source-map,生产环境下使用 source-map
    externals: hasDev ? [nodeExternals()] : [], // 开发环境下排除 node_modules,生产环境下不排除
}

这里我们使用了process.env.NODE_ENV来区分开发环境和生产环境,这样我们就可以使用webpackmode字段来进行区分了;

我们还需要修改一下package.json中的dev指令,例如我这样修改;

json 复制代码
{
  "scripts": {
    "dev:build": "cross-env NODE_ENV=development webpack --mode development --watch",
    "dev:start": "cross-env NODE_OPTIONS=--enable-source-maps nodemon --inspect ./dist/index.js --watch ./dist/index.js",
    "dev": "npm run dev:build | npm run dev:start",
    "build": "cross-env NODE_ENV=production webpack --mode production"
  }
}

这样我们就可以使用npm run build来构建我们的生产环境了,然后使用npm run dev来开发我们的开发环境了;

4. 总结

本章使用webpack来开发node项目,本质上webpack就是一个打包工具,而且webpack也是支持构建node项目的,只是并没有提供开发环境的配置,所以我们需要自己来配置一下;

而实现node开发环境的配置也并没有使用很多高级技巧,都是一些基本的配置,例如source-mapmodeexternals等等;

只要我们明白开发环境和生产环境的区别,我们就可以很轻易的配置我们的开发环境了;

相关推荐
爱吃青椒不爱吃西红柿‍️6 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
一棵开花的树,枝芽无限靠近你10 分钟前
【PPTist】添加PPT模版
前端·学习·编辑器·html
陈王卜13 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
景天科技苑20 分钟前
【vue3+vite】新一代vue脚手架工具vite,助力前端开发更快捷更高效
前端·javascript·vue.js·vite·vue项目·脚手架工具
SameX22 分钟前
HarmonyOS Next 安全生态构建与展望
前端·harmonyos
小行星12531 分钟前
前端预览pdf文件流
前端·javascript·vue.js
小行星12538 分钟前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun0011 小时前
[less] Operation on an invalid type
前端·vue·less·sass·scss
J总裁的小芒果1 小时前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen961 小时前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron