在开发环境中将express.js与Angular CLI连接起来

43

我找到了一篇很棒的教程,讲解了如何使用Angular CLI设置express.js,但是在这个教程中,angular应用程序被编译成生产dist文件夹: https://scotch.io/tutorials/mean-app-with-angular-2-and-the-angular-cli

我该如何将express.js与Angular CLI集成,但我希望express.js能够与Angular应用程序的开发版本配合使用,并且如果我对express或Angular应用程序进行更改,则希望nodemon重新启动。

我已经花费了超过八个小时的时间来尝试使其工作。谢谢!

我不想每次更改Angular应用程序时都运行'ng build'(这需要太长时间) - 我希望在保存对我的angular应用程序或express应用程序进行更改时即时重新加载(就像我正在运行'ng serve'一样)。

我找到了一个教程,可以将Angular 2 QuickStart与Express连接起来,它可以工作,但我想使用Angular CLI。

我知道Angular CLI使用WebPack,而QuickStart使用System.js

7个回答

96

新答案

我的15小时经验告诉我,在开发过程中尝试使用Express提供Angular应用程序并不是一个好主意。正确的方法是在两个不同的端口上运行Angular和Express作为两个不同的应用程序。 Angular将像往常一样在端口4200上提供服务,Express将在端口3000上提供服务。然后为API调用Express应用程序配置代理。

将proxy.config.json添加到Angular项目的根目录中:

{
  "/api/*":{
    "target":"http://localhost:3000",
    "secure":false,
    "logLevel":"debug"
  }
}

打开一个新的终端标签,并运行以下命令启动Express应用程序:

nodemon [YOUR_EXPRESS_APP.js] --watch server

(YOUR_EXPRESS_APP.js通常命名为server.js或app.js。server是您保存所有Express应用程序文件的目录)

打开第二个终端标签,并运行此命令以启动Angular应用程序:

ng serve --proxy-config proxy.config.json

这将确保在任何Angular应用程序文件更改时重新构建和重新加载浏览器中的Angular应用程序。同样,当更改任何Express应用程序文件时,Express服务器将重新启动。

您的Angular应用程序位于此处:http://localhost:4200/

观看此视频以了解如何使用Angular CLI配置API调用的代理

注意: 此设置仅适用于开发环境。在生产中,您需要运行ng build并将Angular应用程序放在dist目录中,由Express提供服务。在生产中,只有一个应用程序正在运行 - 一个Express应用程序提供您的Angular应用程序。

先前的答案:

从@echonax的输入中,我想出了这个解决方案,它非常快:

  • 将Express添加到使用Angular CLI构建的Angular 2应用程序中,如此教程
  • 在终端运行以下命令:

ng build -w & nodemon server.js --watch dist --watch server

这将重新构建Angular应用程序到dist文件夹中,每次发生更改时节点服务器都会重新启动。但是,此设置没有自动浏览器刷新:(

关于此问题请参阅此处:

https://github.com/jprichardson/reload


这让我对ngCli的操作有了更深入的理解。我不想在这里再提供更多答案,但是我最终创建了一个backendfronend文件夹,将ng build生成的index.html复制到这两个文件夹中,然后只需使用node app.js运行我的服务器,并使用ng serve --live-reload=false运行我的构建资源服务器,这样它就不会尝试不断重新连接WDS。我正在研究如何重定向该请求,但现在这种方法似乎可行,并且与此答案类似,只是将后端和前端分离得更加明显。 - Jay
Angular文档现在已经很好地涵盖了此处描述的代理方法。请参阅代理到后端服务器 - Daniel
我正在处理完全相同的问题。您能详细说明为什么不建议在express上提供Angular服务吗?我的第一个想法正是您的答案,再加上Yusuf的并发解决方案(花费了5个小时重新发明轮子..)。但是我想到,从express提供Angular将是更优雅的解决方案,因为它只需要一个服务(?)而且没有代理。这是因为实现的便捷性,还是因为它更正确地反映了生产环境?很想听听您对这个问题的看法。谢谢。 - Namgyu Ho

16

"etayluz" solution很好。但是我想为新回答添加一个选项,以避免打开两次终端。

首先,您必须安装concurrently软件包(https://www.npmjs.com/package/concurrently);

npm install concurrently --save 

接下来,您可以将以下代码添加到您的 package.json 文件中。

"start": "concurrently \"npm run serve-api\" \"npm run serve\"",
"serve": "ng serve --port 3333 --proxy-config proxy.config.json", // You could add --port for changing port
"serve-api": "nodemon [YOUR_EXPRESS_APP.js] --watch server",

npm start 足以运行你的项目。


2
etayluz使用concurrently的解决方案非常完美,运行良好。这是个好主意。 - Gere
这只是用于开发的。同时不要在Heroku和类似平台上工作,因为它们应用“一个容器一个进程”的原则。 - JRichardsz

5
使用angular-cli,ng buildng build --prod命令将为您提供一个捆绑好的文件以及一个index.html文件。让您的app.js(node/express)以此文件为目标。
示例:
app.use( express.static(__dirname + '/src' ) ); //<- it will automatically search for index.html under src folder.

1
@etayluz 如果你在 ng build -w 后面加上 -w,CLI 将会监视客户端的变化,并根据增量重新构建。这样能解决问题吗? - eko
'ng build -w' 运行时间太长了(大约10秒),我想要即时重载。 - etayluz
2
@etayluz 没有 :/ 我会保留我的答案,这样人们就可以了解情况。也许你可以为 angular-cli 提交一个问题? - eko
3
ng build --watch 在第一次运行时需要一些时间,但每次进行更改后,它都可以在1或2秒内编译完成。 - gyc
1
@gyc,这也是我的经验,所以我说“再次重建(根据增量)”,但我猜OP的经历不同。 - eko
显示剩余5条评论

2

更详细的解释

我花了不少时间在自己的开发环境中找出如何实现这个功能。最好的方法是将echonax、squirrelsareduck和Max的解决方案结合起来,利用内置的Angular CLI策略监视前端/Angular更改,并使用nodemon监视后端/Express更改。简而言之,您需要运行两个进程(ng build和nodemon)才能启动和运行开发环境,但它会自动重建并在一个Express Web服务器下运行所有内容。

第一个进程是构建Angular dist文件夹,并监视对Angular前端所做的任何更改。幸运的是,Angular CLI可以使用以下命令本地完成此操作(已测试在Angular CLI >= 1.5):

ng build --watch

您需要将此程序放在后台运行,它将监视Angular代码中所做的任何更改,并实时重建捆绑包。

第二个过程涉及使用nodemon来运行Express服务器,根据您的后端/Express设置的复杂程度,可能需要更多的设置和规划。只需确保Express指向dist文件夹中的索引文件即可。这里的巨大优势是您可以将所有内容添加到Gulpfile中,使用gulp-nodemon在运行nodemon以监视后端/Express之后执行更多顺序任务,例如对后端进行linting、并行运行测试、缩小后端等,或者您可以想到其他任何用途的Gulp。使用npmYarn将nodemon添加到项目的依赖项中,然后运行以下命令启动Express服务器:

nodemon app.js

app.js 替换成你用于构建 Express 后端的文件,这样每当后端发生更改时,它就会重新构建。

tldr;

在后台运行两个独立的进程来启动开发环境。首先运行:

ng build --watch

第二步,将nodemon添加到您的项目依赖项中,并在后台运行以下命令,其中app.js替换为您的Express文件名:
nodemon app.js

奖励

既然你想了解如何自动重新加载浏览器,最好的方法是利用一个名为LiveReload的浏览器插件。由于我们已经使用nodemon来监视后端,如果您还没有使用Gulp运行nodemon和LiveReload作为两个任务,则可以认真考虑使用Gulp。将LiveReload实现到Gulp中的最佳方法是使用gulp-refresh插件,因为这是gulp-livereload插件的更新版本。您将得到一个类似于以下的Gulpfile:

const defaultAssets = require('./config/assets/default'),
  gulp = require('gulp'),
  gulpLoadPlugins = require('gulp-load-plugins'),
  runSequence = require('run-sequence'),
  plugins = gulpLoadPlugins(),
  semver = require('semver');
  
// I store the locations of my backend js files in a config file, so 
// that I can call them later on. ie; defaultAssets
gulp.task('nodemon', function () {
  // Node.js v7 and newer use different debug argument
  const debugArgument = semver.satisfies(process.versions.node, '>=7.0.0') ? '--inspect' : '--debug';

  return plugins.nodemon({
    script: 'app.js',
    nodeArgs: [debugArgument],
    ext: 'js,html',
    verbose: true,
    watch: defaultAssets.server.allJS
  });
});

// Watch Files For Changes
gulp.task('watch', function () {
  // Start LiveReload
  plugins.refresh.listen();

  // Watch backend for changes
  gulp.watch(defaultAssets.server.allJS).on('change', plugins.refresh.changed);
  // Watch frontend dist folder for changes
  gulp.watch('./dist').on('change', plugins.refresh.changed);
});
  
  
gulp.task('default', function (done) {
  runSequence(['nodemon', 'watch'], done);
});

现在,您只需运行gulp命令来启动Express服务器,而不是运行nodemon app.js


1
我也在想这个问题。Max Schwarzmüller在Udemy上的MEAN堆栈课程中有一个示例代码,用于集成Express和Angular。在该示例代码的package.json文件中,使用scripts.build属性为webpack提供了一个命令,该命令监视angular文件并相应地更新。我不想在这里复制他的代码,但这是一般的想法。其余部分将需要一些发现工作。
在自述文件中,他建议运行npm run build来运行webpack,然后在新终端中运行npm start以启动节点服务器。因此理论上,这会像您在答案版本中建议的那样运行两个程序。但是,它采用了更“脚本化”/预定义的方式启动Angular构建过程,而不是导航到Angular子目录并在其中键入ng build --watch,然后单独启动Express应用程序。

0

也许你可以添加一个名为 'concurrently' 的依赖项,或者是 (npm-run-all, parallelshell)。

npm i concurrently --save-dev

然后像这样编辑 package.json 文件:

"scripts": {
        "dev": "concurrently \"ng build -w\"  \"cross-env NODE_ENV=development node .\" "
    }

`这可能会起作用。

参考:

concurrently 示例:https://dev59.com/8V0Z5IYBdhLWcg3w4zkm#30950298

npm-run-all 示例:https://dev59.com/8V0Z5IYBdhLWcg3w4zkm#38213212

parallelshell 示例:https://dev59.com/MlgQ5IYBdhLWcg3wsGCZ#42373547


0
在 src 目录中有一个名为 proxy.conf.json 的文件,其中包含以下代码 -
{
  "/api/*": {
    "target": "http://localhost:3000",
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true
  }
}

通过向 package.json 添加以下 3 个条目进行编辑 -(将back.js替换为您在Angular项目的根目录中的express文件)

"scripts": {
    "client": "ng serve",
    "server": "nodemon back.js",
    "start": "npm-run-all -p client server"
  }

现在运行npm start会同时启动Angular和Express在开发环境中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接