Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught SyntaxError: Cannot use import statement outside a module in Rails project #1765

Closed
ghost opened this issue Nov 11, 2021 · 4 comments

Comments

@ghost
Copy link

ghost commented Nov 11, 2021

In my Rails project I am facing the following issues. The first issue was a known one as in #946 "ReferenceError: require is not defined". By reading through those issues and PR's I've added the following line to my build (with --banner).

--banner:js='import { createRequire as topLevelCreateRequire } from \"module\";\n const require = topLevelCreateRequire(import.meta.url);'

Now the error beneath occurs. I've already tried set the type to module in the package.json etc.

Uncaught SyntaxError: Cannot use import statement outside a module

This is a webapplication requiring some of the commonJS stuff it seems I've also added --platform=node to the build script to fix issues as:

ReferenceError: fs is not defined

Is there a way to bundle this all for the web with all requirements?

{
  "name": "app",
  "type": "module",
  "private": "true",
  "dependencies": {
    "@hotwired/stimulus": "^3.0.1",
    "@hotwired/turbo-rails": "^7.0.1",
    "@nomiclabs/hardhat-ethers": "^2.0.2",
    "@openzeppelin/contracts": "^4.3.2",
    "dotenv": "^10.0.0",
    "esbuild": "^0.13.13",
    "ethers": "^5.0.0",
    "hardhat": "^2.6.8",
    "requirejs": "^2.3.6"
  },
  "scripts": {
    "type": "module",
    "build": "esbuild app/javascript/*.* --bundle --platform=node --outdir=app/assets/builds --banner:js='import { createRequire as topLevelCreateRequire } from \"module\";\n const require = topLevelCreateRequire(import.meta.url);'"
  }
}
@hyrious
Copy link

hyrious commented Nov 11, 2021

To answer your question title, you should know how Node.js treat some file as es modules, either:

  1. in the file's folder (or parent folder), there is package.json with "type": "module"
  2. without 1, let file name end with .mjs

You may know require can not be used in es modules context natively from #946. But both banner or inject won't save you perfectly because once a file is bundled, require() in it can not resolve relative paths correctly, and those files not resolved won't be included in outdir, so you got require(something_wont_be_found).

If your dependencies (not the "dependencies" field in package.json, but libraries your code really depends on) include these dynamic require calls, the best way for esbuild would be you edit these code to "correct" one (not using dynamic require).

@evanw
Copy link
Owner

evanw commented Nov 11, 2021

What you are trying to do is not going to work. Passing --platform=node tells esbuild that you're going to be running the result in node, but then you are running the result in the browser instead. This may break things in a lot of ways. You should be using --platform=browser instead if you are going to be running it in the browser.

ReferenceError: fs is not defined

It sounds like you are trying to use packages that aren't designed to work on the web. There may not be much you can do about that here. If a library needs fs to work, there's no simple fix because there's no equivalent file system on the web. You could try polyfilling it but that sounds pretty complicated. I'm not sure what polyfill to recommend but when you have one, you can try intercepting fs with an esbuild plugin to substitute the path of your polyfill instead: https://esbuild.github.io/plugins/#resolve-callbacks. There's some links about fs polyfills here: webpack/node-libs-browser#72. But you may be better off using some other similar package that is actually intended to be used on the web, or maybe even some other bundler that attempts to polyfill fs for you.

Uncaught SyntaxError: Cannot use import statement outside a module

You can read about how import statements work here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import. Specifically you need <script type="module"> to load code containing import in the browser. That doesn't help you in this case because it sounds like you're trying to import node APIs in the browser, which won't work. But if you did need to load code containing import in the browser, that's how you would do it.

@evanw
Copy link
Owner

evanw commented Jan 22, 2022

Closing due to age.

@evanw evanw closed this as completed Jan 22, 2022
@Jaikant
Copy link

Jaikant commented Apr 6, 2022

I faced a similar error. Adding type=module resolved it.
But what I do not understand is, the code did not give the error for a pure "JS" app, which did the import.
When I moved the code into React, the error popped up. (Which went away when I added type=module).

If anyone knows why?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants