简体   繁体   中英

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

Title was: How do I fix "Cannot use import statement outside a module" error on Heroku without causing a "Must use import to load ES Module" error?

This was before I understood that I was trying to deploy a "static" React "app" and Heroku was running index.js as if it was server code.

I had setup Procfile to contain:

web: node ./src/index.js

Then I saw this error:

...
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)
...

I tried to fix it by adding this to package.json :

  "type": "module",

And then I got this error:

...
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)
...

I should've noted that my React "app" is a front-end only that uses a GraphQL API I've already deployed elsewhere. In other words, there is no "server.js that serves [my] react app". ( HMR 's comment led me to that realization. I guess the correct terminology would be to call this a "static app".)

This code in server.js only slightly adapted from Tin Nguyen 's answer works:

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);

...with this Procfile :

web: node ./server.js

The only change is the path to the build directory, which I tweaked after snooping around with heroku run bash .

My site isn't working properly, but I think that is the result of my build not being correct. Perhaps that can be solved with a buildpack. But that belongs in a different question. (And I might not bother figuring it out since I plan to take Tin Nguyen's advice and try hosting on GitHub.)

Update : The problem wasn't with my build, but with client-side routing (as described on https://create-react-app.dev/docs/deployment/ ). This code (from that page) fixes it (in 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);

The link in HMR's comment helped me reach this understanding, but Dave Ceddia writes that his article covers how to keep a React app and API server together. Is there any documentation on how to deploy a front-end on Heroku (or elsewhere) with an API server already deployed elsewhere?

(I found this answer where Paras recommends Netlify .)

If I am reading it right you have a static website and you want it to be hosted on Heroku.

Static websites can be served on Netlify and also GitHub pages. They don't require a web server. You can still host it on Heroku by wrapping a web server around it that is then serving your static files.

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);

How do you know if you have a static website?
You should have generated build files somewhere in your project. You can navigate to the folder and open index.html . The website should work even though you don't have node or npm running. That folder is in my example ./../build .

Personally I would recommend you host static websites on GitHub over Heroku. Heroku is "free" but with a lot of limitations. The dyno hours are limited, websites need to spin up after not being in use for a long time, etc.

try changing your command:

node ./src/index.js

to:

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

Try for both with and without fix of package.json with

"type": "module"

Actually, this comes from using ES6 import inside the NodeJS environment. there is two way, using require instead of import in the server-side JavaScript files:

import something from 'something';

↓↓↓

const something = require('something');

Or use babel node on the server environment to run the project:

node ./src/index.js

↓↓↓

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

A complete example could be like below:

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

By reading your errors, I guess the second way is better for your case. but at first please remove your solution, I mean the "type": "module", .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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