簡體   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