Сао Ниан, а как насчет Коа и Вебпака?

Node.js JavaScript Egg.js Vue.js React.js koa Webpack внешний фреймворк

Необходимо констатировать, что после прочтения этой статьи многие комментировали некоторый контент, не соответствующий теме статьи.

В этой статье в основном описывается, как беспрепятственно запустить веб-пакет после запуска сервера узла в локальной среде разработки, чтобы добиться интеграции конфигурации внешнего и внутреннего интерфейса.

Он подходит для проектов с полным стеком узла, среднего уровня узла, интерфейсных проектов и т. д.

предисловие

  • В повседневной разработке мы используем инструменты сборки, такие как Webpack для модульной разработки.
  • Или используйте скаффолдинг на основе create-react-app и vue-cli для разработки.
  • Если сейчас нам нужен Node в качестве серверной части, React или Vue в качестве внешнего интерфейса и Webpack в качестве инструмента сборки, не нужно ли нам запускать эти две службы вручную?
  • Поэтому в качестве примеров здесь используются Koa и Webpack.При запуске сервера koa запустите webpack.

Статья довольно длинная, наберитесь терпения

предисловие

Создайте сервер Коа

Создайте сервер веб-пакетов

Есть болевая точка, которую нужно решить

Используйте кластерный процесс

Суммировать

Создайте сервер Коа

Что мне нужно использовать для создания сервера Koa?

  • Разработка интерфейсных шаблонов HTML с использованием KOA-NUNJUCKS-2
  • Обработка статических ресурсов koa-static
  • Обработка внутренней маршрутизации koa-router
  • Обработка сжатия gzip koa-compress

ссылочные зависимости

const Koa = require('koa');
const app = new Koa();
const koaNunjucks = require('koa-nunjucks-2');
const koaStatic = require('koa-static');
const KoaRouter = require('koa-router');
const router = new KoaRouter();
const path = require('path');
const compress = require('koa-compress');

Инициализировать конфигурацию ядра Koa

class AngelConfig {
  constructor(options) {
    this.config = require(options.configUrl);
    this.app = app;
    this.router = require(options.routerUrl);
    this.setDefaultConfig();
    this.setServerConfig();
  }

  setDefaultConfig() {
    //静态文件根目录
    this.config.root = this.config.root ? this.config.root : path.join(process.cwd(), 'app/static');
    //默认静态配置
    this.config.static = this.config.static ? this.config.static : {};
  }

  setServerConfig() {
    //设置端口号
    this.port = this.config.listen.port;
    //cookie签名加密
    this.app.keys = this.config.keys ? this.config.keys : this.app.keys;
  }
}

Наследование реализовано с помощью метода класса Es6. Если вы не знакомы, вы можете обратиться кУчебник Es6

Для конфигурации Koa создайте экземпляр объекта, а затем передайте конфигурацию объекта. Здесь вы можете обратиться к Eggjsconfig.default.jsконфигурация.

Конфигурация создания экземпляра может относиться к следующему

  new AngelServer({
    routerUrl: path.join(process.cwd(), 'app/router.js'),//路由地址
    configUrl: path.join(process.cwd(), 'config/config.default.js') //默认读取config/config.default.js
  })

Настройте промежуточное ПО Koa, включая интерфейсные шаблоны, статические ресурсы, маршрутизацию, сжатие gzip.

//启动服务器
class AngelServer extends AngelConfig {
  constructor(options) {
    super(options);
    this.startService();
  }

  startService() {
    //开启gzip压缩
    this.app.use(compress(this.config.compress));

      //模板语法
    this.app.use(koaNunjucks({
      ext: 'html',
      path: path.join(process.cwd(), 'app/views'),
      nunjucksConfig: {
        trimBlocks: true
      }
    }));
  
    //访问日志
    this.app.use(async (ctx, next) => {
      await next();
      const rt = ctx.response.get('X-Response-Time');
      ctx.logger.info(`angel ${ctx.method}`.green,` ${ctx.url} - `,`${rt}`.green);
    });
    
    // 响应时间
    this.app.use(async (ctx, next) => {
      const start = Date.now();
      await next();
      const ms = Date.now() - start;
      ctx.set('X-Response-Time', `${ms}ms`);
    });
    //路由管理
    this.router({
      router,
      config: this.config,
      app: this.app
    });
  
    this.app.use(router.routes())
      .use(router.allowedMethods());

    // 静态资源
    this.app.use(koaStatic(this.config.root, this.config.static));
  
    // 启动服务器
    this.app.listen(this.port, () => {
      console.log(`当前服务器已经启动,请访问`,`http://127.0.0.1:${this.port}`.green);
    });
  }
}

Здесь могут быть люди, которые не знают, что происходит с моим роутером.
Поделитесь файлом router.js

/**
 *
 * @param {angel 实例化对象} app
 */

const html = require('./controller/home');
const business  = require('./controller/business');

module.exports = (app) => {
  let { router, config } = app;
  router.get('/',html);
  router.post('/system/api/issue/file',business.serverRelease);
  router.post('/system/api/user/reg',business.reg);
  router.get('/system/api/app/list',business.getList)
  router.get('/system/api/server/info',business.getServerInfo)
  router.get('/system/api/server/RAM',business.getServerRAM)
  router.get('/system/api/server/log',business.getServerLog)
}

На самом деле этот роутер тоже относится к методу написания Eggjsrouter.js. На данный момент сервер Koa настроен.

Создайте сервер веб-пакетов

Основной принцип построения веб-пакета заключается в использовании веб-пакета для предоставленияwebpack-dev-middlewareа такжеwebpack-hot-middleware, а затем сотрудничайте с сервисом koa.

Для удобства я использую Koa-WebPack-Dev-Mardware и KOA-WebPack-Hot-Mardware, которые были упакованы на основе KOA.

Сначала введите зависимости

const webpack = require('webpack');
const path = require('path');
const colors = require('colors');

const chokidar = require('chokidar');
const cluster = require('cluster');

const KoaRouter = require('koa-router');
const router = new KoaRouter();
const Koa = require('koa');

const chalk = require('chalk');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const compress = require('koa-compress');

Все то же самое, сначала создайте экземпляр основного класса

//配置核心配置
class AngelCore {
  constructor(options) {
    this.webpackConfig = require(options.url);
    this.config = options.configUrl ? require(options.configUrl) : require(path.join(process.cwd(), 'config/config.default.js'));
  }
  
}

Конфигурация koa-webpack-dev-middleware представлена ​​здесь, см. файл конфигурацииПодробности.

Веб-пакет, который я здесь использую, — это версия webpack@4.x, и наша конфигурация веб-пакета обычно размещается в файле webpack.config.js в корневом каталоге проекта.

Итак, нам нужно поддерживать файл Import WebPack.config.js. Определите класс, который наследует основную конфигурацию

//处理webpack配置
class dealWebpackConfig extends AngelCore {
  constructor(options) {
    super(options);
    this.readConfig();
  }
  //处理webpack环境变量问题
  readConfig() {
    this.webpackConfig.mode = this.config.env.NODE_ENV;
    this.webpackConfig.plugins.push(new ProgressBarPlugin({
      format: ` ٩(๑❛ᴗ❛๑)۶ build [:bar] ${chalk.green.bold(':percent')}  (:elapsed 秒)`,
      complete: '-',
      clear: false
    }));
    this.compiler = webpack(this.webpackConfig); //webpack进度处理完成
    //导入webpack配置
    this.devMiddleware = require('koa-webpack-dev-middleware')(this.compiler, this.config.webpack.options);
    this.hotMiddleware = require('koa-webpack-hot-middleware')(this.compiler);
  }

}
  • Поскольку версия webpack4.x может настраивать переменные среды настройки режима, импортированный файл webpack.config.js был изменен. В то же время был заменен индикатор выполнения при упаковке веб-пакета.

Создайте новый класс для запуска веб-пакета и наследуйте класс DealWebpackConfig.

//运行
class angelWebpack extends dealWebpackConfig {
  constructor(options) {
    super(options);
    this.runWebpack();
  }
  //运行webpack
  runWebpack() {
    app.use(this.devMiddleware);
    app.use(this.hotMiddleware);

  }
}

Затем добавьте служебный порт в веб-пакет, чтобы сервер koa мог получить доступ к статическим ресурсам веб-пакета, порт по умолчанию — 9999.

//重新启动一个koa服务器
class koaServer extends angelWebpack {
  constructor(options) {
    super(options);
    this.startKoa();
  }

  startKoa() {
    
    //fork新进程
    let port = this.config.webpack.listen.port ? this.config.webpack.listen.port : 9999;
    //开启gzip压缩
    app.use(compress(this.config.compress));

    //访问日志
    app.use(async (ctx, next) => {
      await next();
      const rt = ctx.response.get('X-Response-Time');
      console.log(`webpack' ${ctx.method}`.green,` ${ctx.url} - `,`${rt}`.green);
    });

    router.get('/',(ctx) => {
      ctx.body = 'webpack';
    });

    app.use(router.routes()).use(router.allowedMethods());
    app.listen(port, () => {
      console.log('webpack服务器已经启动,请访问',`http://127.0.0.1:${port}`.green);
    });
  }
}

Теперь можно сказать, что веб-пакет настроен.

Есть болевая точка, которую нужно решить

Нам нужен эффект, заключающийся в том, что при изменении внешнего кода веб-пакет перестраивается, а при изменении кода на стороне узла перезапускается служба узла, а именно служба Koa, вместо перезапуска как Koa, так и веб-пакета.

Поэтому здесь используется webpack для использования основного процесса.При запуске webpack запускается сервер koa с рабочим процессом.Перезапуск процесса koa не повлияет на пересборку webpack.

Используйте кластерный процесс

Текущая коа не отслеживает изменения кода, а потом перезапустить коа службу, может понадобиться использовать внешние модулиsupervisorПерезапустите процесс.
Так вот я используюchokidarСледите за тем, был ли изменен файл nodejs, затем убивайте процесс koa и повторно разветвляйте процесс на новый рабочий процесс. Поэтому измените класс koaServer выше.

  class koaServer extends angelWebpack {
  constructor(options) {
    super(options);
    this.startKoa();
  }

  startKoa() {
    
    //fork新进程
    let port = this.config.webpack.listen.port ? this.config.webpack.listen.port : 9999;
    //开启gzip压缩
  
    app.use(compress(this.config.compress));

    //访问日志
    app.use(async (ctx, next) => {
      await next();
      const rt = ctx.response.get('X-Response-Time');
      console.log(`webpack' ${ctx.method}`.green,` ${ctx.url} - `,`${rt}`.green);
    });

    router.get('/',(ctx) => {
      ctx.body = 'webpack';
    });

    app.use(router.routes()).use(router.allowedMethods());
    //监听和重启服务。
    this.watchDir();
    app.listen(port, () => {
      console.log('webpack服务器已经启动,请访问',`http://127.0.0.1:${port}`.green);
    });
  }

  watchDir() {
    let worker = cluster.fork();
    const watchConfig = {
      dir: [ 'app', 'lib', 'bin', 'config'],
      options: {}
    };
    chokidar.watch(watchConfig.dir, watchConfig.options).on('change', filePath =>{
      console.log(`**********************${filePath}**********************`);
      worker && worker.kill();
      worker = cluster.fork().on('listening', (address) =>{
        console.log(`[master] 监听: id ${worker.id}, pid:${worker.process.pid} ,地址:http://127.0.0.1:${address.port}`);
      });
    });
  }

}

Наконец, вызовите его единообразно в файле записи службы

//fork一个新的进程,用于启动webpack
if(cluster.isMaster) {
  new angelWebpack({
    url: path.join(process.cwd(), 'assets/webpack.config.js'), //webpack配置地址
    configUrl: path.join(process.cwd(), 'config/config.default.js') //默认读取config/config.default.js
  });

}

// 启动angel服务
if(cluster.isWorker) {
  new AngelServer({
    routerUrl: path.join(process.cwd(), 'app/router.js'),//路由地址
    configUrl: path.join(process.cwd(), 'config/config.default.js') //默认读取config/config.default.js
  })
}
  


Суммировать

Наконец, здесь представлена ​​только среда для среды разработки.Если это производственная среда, вам необходимо удалить слой веб-пакета и использовать koa в качестве основного процесса.Конечно, nodejs работает только в одном процессе, поэтому эта служба koa не может полностью использовать всю производительность машины.

Конечно, есть и способы решения этой болевой точки: при запуске сервера разветвляйте несколько процессов для обработки бизнес-логики, каждый раз, когда приходит запрос, процесс выделяется для запуска, после завершения бизнес-логики процесс закрывается. , а основной процесс разветвляет процесс. Максимизируйте производительность машины.

Исходный код сервиса Koa и сервиса webpack в моемGithub, добро пожаловать звезда.

================================================== === ========================== Вы можете увидеть мой другой постКак создать надежный и стабильный веб-сервер