繁体   English   中英

如何将静态 React“应用程序”部署到 Heroku?

[英]How do I deploy a static React "app" to Heroku?

标题是:如何在 Heroku 上修复“无法在模块外使用导入语句”错误而不会导致“必须使用导入来加载 ES 模块”错误?

这是在我理解我试图部署一个“静态”React“应用程序”之前,Heroku 正在运行 index.js,就好像它是服务器代码一样。

我已经设置Procfile来包含:

web: node ./src/index.js

然后我看到了这个错误:

...
2020-03-29T02:34:01.000000+00:00 app[api]: Build succeeded
2020-03-29T02:34:02.637867+00:00 heroku[web.1]: State changed from starting to crashed
2020-03-29T02:34:02.622526+00:00 heroku[web.1]: Process exited with status 1
2020-03-29T02:34:02.583667+00:00 app[web.1]: /app/src/index.js:1
2020-03-29T02:34:02.583689+00:00 app[web.1]: import React from 'react';
2020-03-29T02:34:02.583690+00:00 app[web.1]: ^^^^^^
2020-03-29T02:34:02.583690+00:00 app[web.1]:
2020-03-29T02:34:02.583691+00:00 app[web.1]: SyntaxError: Cannot use import statement outside a module
2020-03-29T02:34:02.583691+00:00 app[web.1]: at wrapSafe (internal/modules/cjs/loader.js:1072:16)
...

我试图通过将其添加到package.json来修复它:

  "type": "module",

然后我收到了这个错误:

...
2020-03-29T03:05:01.000000+00:00 app[api]: Build succeeded
2020-03-29T03:05:06.293573+00:00 heroku[web.1]: Starting process with command `node ./src/index.js`
2020-03-29T03:05:08.744086+00:00 heroku[web.1]: State changed from starting to crashed
2020-03-29T03:05:08.724957+00:00 heroku[web.1]: Process exited with status 1
2020-03-29T03:05:08.650103+00:00 app[web.1]: internal/modules/cjs/loader.js:1174
2020-03-29T03:05:08.650125+00:00 app[web.1]: throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
2020-03-29T03:05:08.650126+00:00 app[web.1]: ^
2020-03-29T03:05:08.650126+00:00 app[web.1]:
2020-03-29T03:05:08.650126+00:00 app[web.1]: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /app/src/index.js
2020-03-29T03:05:08.650127+00:00 app[web.1]: at Object.Module._extensions..js (internal/modules/cjs/loader.js:1174:13)
2020-03-29T03:05:08.650127+00:00 app[web.1]: at Module.load (internal/modules/cjs/loader.js:1002:32)
...

我应该注意到我的 React “应用程序”只是一个前端,它使用了我已经部署在其他地方的 GraphQL API。 换句话说,没有“为 [我的] 反应应用程序提供服务的 server.js”。 HMR的评论让我意识到了这一点。我想正确的术语是将其称为“静态应用程序”。)

server.js这段代码仅稍微改编自Tin Nguyen的回答作品:

const http = require('http');
const path = require('path');
const express = require('express');

let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './build')));

server = new http.createServer(app);

server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);

...使用此Procfile

web: node ./server.js

唯一的变化是构建目录的路径,我在使用heroku run bash窥探后对其进行了调整。

我的网站工作不正常,但我认为这是我的构建不正确的结果。 也许这可以通过 buildpack 解决。 但这属于另一个问题。 (而且我可能不会费心去弄清楚,因为我打算听取 Tin Nguyen 的建议并尝试在 GitHub 上托管。)

更新:问题不在于我的构建,而在于客户端路由(如https://create-react-app.dev/docs/deployment/ 所述)。 此代码(来自该页面)修复了它(在server.js ):

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/*', function (req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(process.env.PORT);

HMR 评论中链接帮助我达成了这种理解,但 Dave Ceddia 写道,他的文章涵盖了如何将 React 应用程序和 API 服务器保持在一起。 是否有关于如何使用已部署在其他地方的 API 服务器在 Heroku(或其他地方)上部署前端的文档?

(我在Paras推荐Netlify 的地方找到了这个答案。)

如果我没看错,您有一个静态网站,并且希望将其托管在 Heroku 上。

静态网站可以在 Netlify 和 GitHub 页面上提供服务。 他们不需要网络服务器。 您仍然可以通过在它周围包裹一个 Web 服务器来将它托管在 Heroku 上,然后该服务器为您的静态文件提供服务。

const http = require('http');
const path = require('path');
const express = require('express');

let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './../build')));

server = new http.createServer(app);

server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);

你怎么知道你有一个静态网站?
您应该在项目中的某处生成了构建文件。 您可以导航到该文件夹​​并打开index.html 即使您没有运行nodenpm该网站也应该可以工作。 该文件夹在我的示例./../build

我个人建议您通过 Heroku 在 GitHub 上托管静态网站。 Heroku 是“免费的”,但有很多限制。 dyno 时间有限,网站长时间不使用后需要启动等等。

尝试更改您的命令:

node ./src/index.js

到:

node --experimental-modules ./src/index.js

尝试使用和不使用 package.json 修复

"type": "module"

实际上,这来自在 NodeJS 环境中使用 ES6 import 有两种方法,在服务器端 JavaScript 文件中使用require而不是import

import something from 'something';

↓↓↓

const something = require('something');

或者在服务端环境使用babel node运行项目:

node ./src/index.js

↓↓↓

babel-node [options] [ -e script | ./src/index.js ] [arguments]

一个完整的例子可能如下所示:

npx babel-node --presets es2015 -- ./src/index.js

通过阅读您的错误,我想第二种方法更适合您的情况。 但首先请删除您的解决方案,我的意思是"type": "module",

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM