Graphql + Node 实践(一):环境搭建

1,677 阅读3分钟

1. 搭建 typescript + webpack + nodemon 的运行环境

0. 需求分析

我们想要啥效果:

  • 支持es6+ -> babel-loader + webpack
  • 支持typescript -> ts-loader
  • client文件夹下的前端文件多入口打包(便于懒加载) -> webpack多入口配置
  • server下的文件能通过webpack打包,当对应文件更新时,实现服务器重启 -> 使用nodemon来定位变化

1. 安装依赖

yarn init

yarn add babel-loader @babel/core @babel/preser-env ts-loader --save-dev

yarn add nodemon -g

yarn add webpack webpack-merge --save-dev

yarn add webpack-cli webpack-dev-server -g

2. 创建文件目录

文件目录

3. 配置webpack基础配置

1. client 代码打包配置
// webpack.config.js
// 通用的基础loader等配置
const path = require("path");
const fs = require("fs");

module.exports = {
  devtool: "inline-source-map",
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "../src/"),
    },
    extensions: [".ts", ".tsx", ".js"],
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        options: {
          preset: ["@babel/preset"],
        },
      },
      {
        test: /\.tsx?$/,
        loader: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
};

// 获取多文件入口
// dirConfig.js
const fs = require("fs");
const path = require("path");

// 为了获得client文件夹下多文件的入口
// 便于分包,按需加载
module.exports = function getFilePath(basePath) {
  const files = [];

  function _tranvers(_basePath) {
    const _dirPath = fs.readdirSync(_basePath);

    _dirPath.map((filePath) => {
      const currPath = path.resolve(_basePath, filePath);
      const isDir = fs.statSync(currPath).isDirectory();
      if (isDir) {
        _tranvers(currPath);
      } else {
        files.push(currPath);
      }
    });
  }
  _tranvers(basePath);

  return files.reduce((p, c, i) => ({ ...p, [i]: c }), {});
};

// develoment 开发模式配置
// 多文件打包的好处就是 如果我们只改动了其中一个文件,其他的文件不需要重新打包
// webpack.config.dev.js
const { merge } = require("webpack-merge");
const common = require("./webpack.config.js");
const path = require("path");
const getFilePath = require("./dirConfig");
const clientPath = path.resolve(__dirname, "../src/client");

const fileList = getFilePath(clientPath);

module.exports = merge(common, {
  mode: "development",
  entry: fileList,
  // 输出文件按照多文件打包
  output: {
    path: path.resolve(__dirname, "../dist"),
    // 这里使用chunckhash,是包的版本,如果包没有被更新他的chunck是不会变的~
    filename: "[name].[chunkhash].js",
  },
  // 启用webpack-dev-server
  devServer: {
    contentBase: path.resolve(__dirname, "../dist"),
  },
});

2. node server配置

注意点:

  • target设为node,告诉webpack node的通用模块可以不用打进去
const { merge } = require("webpack-merge");
const common = require("./webpack.config.js");
const path = require("path");

module.exports = merge(common, {
  target: "node",
  entry: path.resolve(__dirname, "../src/server/index.ts"),
  output: {
    path: path.resolve(__dirname, "../local"),
    filename: "server.js",
  },
  node: {
    console: true,
    process: true,
    global: true,
    Buffer: true,
    __filename: true,
    __dirname: true,
  },
  mode: "development",
});
  • 简单的编写下node server的代码

    import express from "express";
    import nunjucks from "nunjucks";
    import path from "path";
    
    const app = express();
    
    app.set("view engine", "njk");
    nunjucks.configure(path.resolve(__dirname, "./view/"), {
      autoescape: true,
      express: app,
    });
    
    app.get("/", (req, res) => {
      res.send("hello Word")
    });
    
    
    app.listen(3000, () => {
      console.log("server is work on 3000");
    });
    
    

3. 测试配置结果
  1. 先在package.json中添加打包的命令

  1. 看一看client下面的文件打包结果,从这里可以看到,我们的三个文件已经被打成了3个不同的js包完成了 ts -> js -> 多入口打包,

  2. 这个时候我们修改其中一个user/index.ts文件我们发现修改文件后 chunckName为2的被重新打包,而其他的文件并没有被重新打包,其chunkHash值并没有发生改变

  1. server端的打包结果,可以看到node的原生模块作为了external,理论上没有被打进来

4. 配置nodemon

1. nodemon是啥玩意儿?

nodemon是啥: Nodemon is a utility that will monitor for any changes in your source and automatically restart your server. Perfect for development.

说人话:

nodemon 就是在你服务器代码更新的时候帮你重启服务器。

以前的场景:node代码改了之后,手动yarn start一下

现在:node代码改了之后,自动start (就是这么简单~)

2.项目中的nodemon配置
{
  // 是否支持重启动
  "restartable": "rs",
  // 配置忽略的文件 -> 这些文件改动之后不会重启服务器
  "ignore": [".git", ".svn", "node_modules/**/node_modules"],
  "verbose": true,
  // 我们执行nodemon xxx.ts 他会用ts-node执行, 执行nodemon xxx.js用node xxx.js执行
  // 执行的配置列表
  "execMap": {
    "js": "node --harmony",
    "ts": "ts-node"
  },
  // 我们打包的文件在local文件下
  // 我们写的文件在server下
  // 这是一个监听列表,只有监听列表下的文件发生变化,才会重启node服务
  "watch": ["./local", "./src/server"],
  "env": {
    "NODE_ENV": "development"
  },
  // 监听文件的后缀名,只有包含在下列扩展名内的文件才会重启node服务
  // 比如一个server下的 xxx.html发生更改,他是不会重启node服务的
  "ext": "js json njk"
}

5. 整体搭建环境测试

# 现在我们通过三个命令去启动我们的环境
yarn dev-serve
yarn dev-client
yarn watch-serve

当我们修改index.ts的时候,会自动重新打包并通过nodemon重启node服务

好了辛苦了半天终于把环境搭好了后面就开始正式实践 node + Graphql