【问题标题】:Node.js - SyntaxError: Unexpected token importNode.js - SyntaxError:意外的令牌导入
【发布时间】:2019-08-07 09:44:36
【问题描述】:

我不明白出了什么问题。 节点 v5.6.0 NPM v3.10.6

代码:

function (exports, require, module, __filename, __dirname) {
    import express from 'express'
};

错误:

SyntaxError: Unexpected token import
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:387:25)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:140:18)
    at node.js:1001:3

【问题讨论】:

  • 使用像 Babel 这样的转译器在 Nodejs 中使用 import,因为它在 nodejs 中不被原生支持。最好的 import 替代方法是 require 所以去吧。
  • 结帐支持 import () nodejs v16 - nodejs.org/api/packages.html

标签: javascript node.js npm ecmascript-6


【解决方案1】:

节点 13+ 由于 Node 13,您可以使用 .mjs 扩展名,或在 package.json 中设置 {"type": "module"}。您不需要使用--experimental-modules 标志。 Modules is now marked as stable in node.js

节点 12 由于 Node 12,您可以使用 .mjs 扩展名,或在 package.json 中设置 "type": "module"。您需要使用--experimental-modules 标志运行节点。

节点 9Node 9 中,它在标志后面启用,并使用.mjs 扩展。

node --experimental-modules my-app.mjs

虽然import 确实是 ES6 的一部分,遗憾的是,默认情况下 NodeJS 还不支持它,并且只是最近才在浏览器中获得支持。

请参阅 browser compat table on MDNthis Node issue

来自 James M Snell 的 Update on ES6 Modules in Node.js(2017 年 2 月):

工作正在进行中,但需要一些时间 — 我们目前正在考虑至少一年左右。

在原生支持 (now marked stable in Node 13+) 之前,您必须继续使用经典的 require 语句

const express = require("express");

如果你真的想在 NodeJS 中使用新的 ES6/7 特性,你可以使用 Babel 编译它。 Here's an example server.

【讨论】:

  • 有谁知道 node 10 是否会默认启用支持? (预计下个月出道)
  • @Scimonster......node --experimental-modules my-app.mjs (node:12176) ExperimentalWarning:ESM 模块加载器是实验性的。 { 错误:在搜索中找不到模块 /C:/Users/WittyParrot/Documents/card-test-project/src/my-app.mjs (internal/modules/esm/DefaultResolve.js:23:12)test-project/搜索时的 src/my-app.mjs (internal/modules/esm/DefaultResolve.js:23:12)....抛出警告找不到 my-app.js....请建议....我安装节点版本 9.11.1
  • 在 v12 中仍然需要一个标志 nodejs.org/api/esm.html#esm_ecmascript_modules
  • 似乎 Node v13.2.0 无法将 ES 模块导入或导入()为“.js”,除非在其上方有一个带有 type: module 的 package.json。 esm 在这些情况下仍然有用。
  • 离题,但我无法安装节点 14,因为它不再支持 Windows 7。很遗憾,如果我想要完全支持导入/导出而没有任何标志,那么我必须升级我的操作系统。
【解决方案2】:

我一直在努力让它发挥作用。以下是有效的:

  1. 使用最新的节点版本。我正在使用 v14.15.5。通过运行验证您的版本: node --version
  2. 为文件命名,使它们都以 .mjs 而不是 .js 结尾

示例:

mod.mjs

export const STR = 'Hello World'

test.mjs

import {STR} from './mod.mjs'
console.log(STR)

运行: node test.mjs

您应该会看到“Hello World”。

【讨论】:

    【解决方案3】:

    我的项目使用 node v10.21.0,仍然不支持 ES6 import 关键字。有多种方法可以让节点识别import,其中之一是使用node --experimental-modules index.mjs 启动节点(mjs 扩展名已经包含在此处的答案之一中)。但是,这样一来,您将无法在代码中使用特定于节点的关键字,例如 require。如果需要同时使用 nodejs 的 require 关键字和 ES6 的 import,那么出路是使用 esm npm 包。添加 esm 包作为依赖后,需要使用特殊配置启动节点,例如:node -r esm index.js

    【讨论】:

      【解决方案4】:

      从 14.x LTS 版本开始,Node 的稳定版本支持import 语句。

      您需要做的就是在package.json 中指定"type": "module"

      【讨论】:

      • 我使用节点 14.17.5 但不能使用import
      • 支持。但并非没有额外的配置。您仍然需要像我提到的那样指定"type": "module",或者为您的文件使用.mjs 扩展名。
      【解决方案5】:

      只需安装更高版本的 Node.js。不支持 Node v10 es6。您需要禁用一些标志或使用

      【讨论】:

      【解决方案6】:

      我将在原始问题中解决其他人没有的另一个问题。最近在我自己的 NodeJS 项目中从 CommonJS 转换为 ESM 之后,我几乎没有看到有人讨论过你不能将导入放在任何你想要的地方,就像你可以使用 require 一样。我的项目现在可以很好地使用导入,但是当我使用问题中的代码时,我首先收到一个错误,因为没有命名函数。命名函数后,我收到以下内容...

      import express from 'express'
             ^^^^^^^
      
      SyntaxError: Unexpected identifier
          at Loader.moduleStrategy (internal/modules/esm/translators.js:88:18)
      

      您不能像您需要的那样将导入放置在函数中。它们必须放在文件的顶部,在代码块之外。我自己在这个问题上浪费了不少时间。

      因此,尽管上述所有答案都非常适合帮助您在项目中使用导入,但没有一个答案可以解决原始问题中的代码无法按书面形式工作的事实。

      【讨论】:

        【解决方案7】:

        错误: SyntaxError: Unexpected token import or SyntaxError: Unexpected token export


        解决方案:更改所有导入作为示例

        const express               = require('express');
        const webpack               = require('webpack');
        const path                  = require('path');
        const config                = require('../webpack.config.dev');
        const open                  = require('open');
        

        并将您的 export default = foo; 更改为 module.exports = foo;

        【讨论】:

        • 我希望您能多解释一下导出默认部分。我在这部分遇到了麻烦。导入非常适合您的回答。
        • 我的答案之前有一个答案,其中有一个解释。但是为了澄清 Node 不支持 ES6 语法。当您说 Import ... 时,您使用的是 ES6 语法
        【解决方案8】:

        正如其他答案中提到的,Node JS 目前不支持 ES6 导入。

        (截至目前,请阅读 EDIT 2)

        Enable ES6 imports in node js 提供了此问题的解决方案。我已经尝试过了,它对我有用。

        运行命令:

            npm install babel-register babel-preset-env --save-dev
        

        现在您需要创建一个新文件 (config.js) 并将以下代码添加到其中。

            require('babel-register')({
                presets: [ 'env' ]
            })
            // Import the rest of our application.
            module.exports = require('./your_server_file.js')
        

        现在您可以编写导入语句而不会出现任何错误。

        希望这会有所帮助。

        编辑:

        您需要运行使用上述代码创建的新文件。就我而言,它是config.js。所以我必须跑:

            node config.js
        

        编辑 2:

        在试验过程中,我发现了一个简单的解决方案。

        在项目的根目录中创建.babelrc 文件。

        添加以下(以及您需要的任何其他 babel 预设,可以在此文件中添加):

            {
                "presets": ["env"]
            }
        

        使用命令npm install babel-preset-env --save安装babel-preset-env,然后使用命令npm install babel-cli -g --save安装babel-cli

        现在,转到您的服务器或索引文件所在的文件夹并使用以下命令运行: babel-node 文件名.js

        或者您可以通过将以下代码添加到您的package.json 文件来使用npm start 运行:

            "scripts": {
                "start": "babel-node src/index.js"
            }
        

        【讨论】:

        【解决方案9】:

        我很震惊esm 没有被提及。这个小而强大的包允许您使用importrequire

        在您的项目中安装 esm

        $ npm install --save esm

        更新您的节点启动脚本以使用 esm

        node -r esm app.js

        esm 可以正常工作。我在.mjs--experimental-modules 上浪费了大量时间,却发现.mjs 文件无法导入使用requiremodule.exports 的文件。这是一个大问题,而 esm 允许您混合搭配,它只是想出来...... esm 只是工作。

        【讨论】:

        • 如何使用 esm 通过 Visual Studio Code 调试器进行调试?我想直接按F5开始调试VSCode中的js。
        • 如果您使用的是 nodemon,请将您的 npm 脚本更新为 nodemon -r esm app.js 以使用此解决方案自动重新加载。
        • 哇。我不相信这是真的,但确实如此。
        【解决方案10】:

        当我开始使用 express 时,我一直想要一个使用 import 而不是 require 的解决方案

        const express = require("express");
        // to 
        import express from "express"
        

        很多时候都经过这条线:-Unfortunately, Node.js doesn't support ES6's import yet.

        现在为了帮助其他人,我在这里创建了两个新的解决方案

        1) esm:-

        非常简单、无 babel、无捆绑的 ECMAScript 模块加载器。 让我们让它工作

          yarn add esm / npm install esm
        

        创建 start.js 或使用你的命名空间

         require = require("esm")(module/*, options*/)
         // Import the rest of our application.
         module.exports = require('./src/server.js')
         // where server.js is express server start file
        

        更改package.josnstart.js 传递路径

          "scripts": {
            "start": "node start.js",
            "start:dev": "nodemon start.js",
          },
          "dependencies": {
        +    "esm": "^3.2.25",
          },
          "devDependencies": {
        +   "nodemon": "^1.19.2"
          }
        

        2) Babel js:-

        这可以分为两部分

        a) Solution 1 感谢 timonweb.com

        b) 解决方案 2

        使用Babel 6(旧版babel-preset-stage-3 ^6.0) 在您的根文件夹中创建.babelrc 文件

        {
            "presets": ["env", "stage-3"]
        }
        

        安装 babel-preset-stage-3

        yarn add babel-cli babel-polyfill babel-preset-env bable-preset-stage-3 nodemon --dev
        

        package.json 的变化

        "scripts": {
        +   "start:dev": "nodemon --exec babel-node -- ./src/index.js",
        +   "start": "npm run build && node ./build/index.js",
        +   "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
        +   "clean": "rm -rf build && mkdir build"
        },
        "devDependencies": {
        +    "babel-cli": "^6.26.0",
        +    "babel-polyfill": "^6.26.0",
        +    "babel-preset-env": "^1.7.0",
        +    "babel-preset-stage-3": "^6.24.1",
        +    "nodemon": "^1.19.4"
        },
        

        启动你的服务器

        yarn start / npm start
        

        哦,不,我们创建了新问题

        regeneratorRuntime.mark(function _callee(email, password) {
        ^
        ReferenceError: regeneratorRuntime is not defined
        

        仅当您在代码中使用 async/await 时才会出现此错误。 然后使用包含自定义再生器运行时和 core-js 的 polyfill。 在index.js 上添加

        import "babel-polyfill"
        

        这允许你使用 async/await

        使用Babel 7

        需要更新项目中的所有内容 让我们从 babel 7 开始 .babelrc

        {
          "presets": ["@babel/preset-env"]
        }
        

        package.json 的一些变化

        "scripts": {
        +  "start:dev": "nodemon --exec babel-node -- ./src/index.js",
        +  "start": "npm run build && node ./build/index.js",
        +  "build": "npm run clean && babel src -d build -s --source-maps --copy-files",
        +  "clean": "rm -rf build && mkdir build",
            ....
        }
        "devDependencies": {
        +   "@babel/cli": "^7.0.0",
        +   "@babel/core": "^7.6.4",
        +   "@babel/node": "^7.0.0",
        +   "@babel/polyfill": "^7.0.0",
        +   "@babel/preset-env": "^7.0.0",
        +   "nodemon": "^1.19.4"
        ....
        }
        

        并在起点使用import "@babel/polyfill"

        import "@babel/polyfill"
        import express from 'express'
        const app = express()
        
        //GET request
        app.get('/', async (req, res) {
          // await operation
          res.send('hello world')
        })
        app.listen(4000, () => console.log('? Server listening on port 400!'))
        

        你在想为什么start:dev

        说真的。如果你是新手,这是个好问题。每次更改您都对启动服务器很感兴趣 然后使用yarn start:dev作为开发服务器每次更改都会自动重启服务器以获取更多关于nodemon的信息

        【讨论】:

          【解决方案11】:

          从 Node.js v12 开始(现在这可能相当稳定,但仍标记为“实验性”),您有几个使用 ESM 的选项(ECMAScript Modules)在 Node.js 中(对于文件,还有第三种评估字符串的方法),the documentation 是这样说的:

          --experimental-modules 标志可用于启用对 ECMAScript 模块(ES 模块)。

          一旦启用,Node.js 将在传递给时将以下内容视为 ES 模块 node 作为初始输入,或者当被 import 语句引用时 ES模块代码:

          • .mjs 结尾的文件。

          • .js 结尾的文件,或无扩展名的文件,当最近的父 package.json 文件包含一个顶级字段 "type",其值为 "module".

          • 作为参数传入 --eval--print 的字符串,或通过管道传递给 node 通过STDIN,带有标志--input-type=module

          Node.js 会将所有其他形式的输入视为 CommonJS,例如 .js 文件 其中最近的父 package.json 文件不包含顶级 "type" 字段或不带标志 --input-type 的字符串输入。这种行为是为了 保持向后兼容性。但是,现在 Node.js 支持两者 CommonJS 和 ES 模块,最好尽可能显式。节点.js 当传递给 node 作为初始输入时,会将以下内容视为 CommonJS, 或者当 ES 模块代码中的 import 语句引用时:

          • .cjs 结尾的文件。

          • .js 结尾的文件,或无扩展名的文件,当最近的父 package.json 文件包含一个顶级字段 "type",其值为 "commonjs".

          • 作为参数传入 --eval--print 的字符串,或通过管道传递给 node 通过STDIN,带有标志--input-type=commonjs

          【讨论】:

            【解决方案12】:

            babel 7 提案 你能添加开发依赖项吗

            npm i -D @babel/core @babel/preset-env @babel/register
            

            并在根目录中添加一个 .babelrc

            {
            "presets": [
              [
                "@babel/preset-env",
                {
                  "targets": {
                    "node": "current"
                 }
                }
              ]
             ]
            }
            

            并添加到 .js 文件中

            require("@babel/register")
            

            或者如果你在 cli 中运行它,你可以使用 require 钩子作为 -r @babel/register,例如

            $node -r @babel/register executeMyFileWithESModules.js
            

            【讨论】:

            • 安装 @babel/preset-env 并将其添加到 .babelrc 就成功了。在我的情况下不需要@babel/register 插件。
            【解决方案13】:

            如果您仍然无法使用“导入”,我是这样处理的: 只需将其转换为节点友好的需求即可。示例:

            import { parse } from 'node-html-parser';
            

            等同于:

            const parse = require('node-html-parser').parse;
            

            【讨论】:

            • 如果您(很可能是这种情况)使用export 关键字,则不正确
            • @DanielThompson 抱歉,如果这可能是误解,我只是为这种情况提供一个解决方法,如果您在没有 export 关键字的情况下工作,无论如何感谢您的帮助!
            • 为我工作。谢谢
            【解决方案14】:

            在我的例子中,它正在处理.babelrc 文件,它应该包含如下内容:

            {
              "presets": ["es2015-node5", "stage-3"],
              "plugins": []
            }
            

            【讨论】:

              【解决方案15】:

              如果您可以使用 'babel',请尝试在 package.json(--presets=es2015) 中添加构建脚本,如下所示。它将导入代码预编译到 es2015

              "build": "babel server --out-dir build --presets=es2015 && webpack"
              

              【讨论】:

              • 但我对npm start 的调用会先进行“构建”,还是先进行“开始”? (当前定义开始:"nodemon src/app.js --exec \"npm run lint && node\"",
              • 如果我运行这个 cmd,它会显示服务器不存在错误
              【解决方案16】:

              很遗憾,Node.js 还不支持 ES6 的 import

              要完成你想要做的事情(导入 Express 模块),这段代码就足够了

              var express = require("express");
              

              另外,请确保您已通过运行安装 Express

              $ npm install express
              

              有关学习 Node.js 的更多信息,请参阅Node.js Docs

              【讨论】:

              • import 不一定是 TypeScript 的特性。 TypeScript 是带有类型的 ES6。所以像 import 这样的东西是 ES6 原生的。
              • Node 现在原生支持这个,所以这个答案已经过时了
              猜你喜欢
              • 2018-11-10
              • 2018-09-24
              • 1970-01-01
              • 2018-07-14
              • 1970-01-01
              相关资源
              最近更新 更多