Node.js - Błąd składni: nieoczekiwany import tokena

443

Nie rozumiem co jest nie tak. Węzeł v5.6.0 NPM v3.10.6

Kod:

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

Błąd:

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
SofDroid
źródło
4
Użyj transpilatora takiego jak Babel, aby użyć importu w Nodejs, ponieważ nie jest on natywnie obsługiwany w nodejs. Istnieje najlepsza alternatywa dla importu, więc należy to zrobić.
BHUVNESH KUMAR

Odpowiedzi:

484

Aktualizacja 3: Od Węzła 13 możesz użyć rozszerzenia .mjs lub ustawić „type”: „module” w pliku package.json. Ci nie muszą korzystać z --experimental-modulesflagą.

Aktualizacja 2: Od Węzła 12 możesz użyć .mjsrozszerzenia lub ustawić "type": "module"w pliku package.json. I musisz uruchomić węzeł z --experimental-modulesflagą.

Aktualizacja: W węźle 9 , jest on włączony za flagą, i używa .mjsrozszerzenia.

node --experimental-modules my-app.mjs

Chociaż importjest rzeczywiście częścią ES6, niestety nie jest jeszcze domyślnie obsługiwany w NodeJS i dopiero niedawno otrzymał wsparcie w przeglądarkach.

Zobacz tabelę kompatybilności przeglądarki w MDN i ten problem z węzłem .

Z aktualizacji Jamesa M. Snella w sprawie modułów ES6 w Node.js (luty 2017 r.):

Prace są w toku, ale zajmie to trochę czasu - obecnie obserwujemy co najmniej około roku.

Dopóki wsparcie nie pojawi się natywnie, będziesz musiał nadal używać klasycznych requireinstrukcji:

const express = require("express");

Jeśli naprawdę chcesz korzystać z nowych funkcji ES6 / 7 w NodeJS, możesz je skompilować za pomocą Babel. Oto przykładowy serwer .

Scimonster
źródło
2
czy ktoś wie, czy węzeł 10 zostanie dostarczony z domyślnie włączoną obsługą? (debiut w przyszłym miesiącu)
Hartmut
2
@ Scimonster ...... node --experimental-modules my-app.mjs (node: 12176) ExperimentalWarning: Moduł ładujący ESM jest eksperymentalny. {Błąd: nie można znaleźć modułu /C:/Users/WittyParrot/Documents/card-test-project/src/my-app.mjs w wyszukiwaniu (wewnętrzny / moduły / esm / DefaultResolve.js: 23: 12) test-project / src / my-app.mjs at search (wewnętrzna / moduły / esm / DefaultResolve.js: 23: 12) .... rzucając ostrzeżenie nie można znaleźć my-app.js .... proszę zasugerować ... i zainstalowana wersja węzła 9.11.1
Leo

52
frustrujące, ponieważ większość samouczków mówi o używaniu importu, ale prawie nie ma wsparcia dla tego. (Chcę 2 godziny mojego życia z powrotem lol)
kiwicomb123

9
@ChaimEliyah: dostałem ten sam problem w węźle v11.0.0
whoami

5
Nadal wymaga flagi w wersji 12 nodejs.org/api/esm.html#esm_ecmascript_modules
ABabin

60

Niestety, Node.js nie obsługuje importjeszcze ES6 .

Aby zrealizować to, co próbujesz zrobić (zaimportuj moduł Express), ten kod powinien wystarczyć

var express = require("express");

Upewnij się również, że masz zainstalowany Express, uruchamiając

$ npm install express

Zobacz Dokumenty Node.js, aby uzyskać więcej informacji na temat nauki Node.js.


8
importniekoniecznie jest funkcją TypeScript. TypeScript to ES6 z czcionkami. Więc rzeczy takie jak import są natywne ES6.
borislemke

@borislemke To prawda, źle zinterpretowałem OP. :) Zmienię to.
baranskistad

cześć, zainstalowałem ekspres, ale w skrypcie pliku package.json co powinniśmy napisać? Jeśli napiszę „skrypty”: {„start”: „node index.js”}, powinien wyświetlać ten sam błąd. proszę pomóż mi.
Ravi Shah
node index.jsdziała dla mnie, ale kiedy biegnę node dist/main.js, też dostaję Unexpected token import.
TheFox
@ TheFox prawdopodobnie masz import w tym pliku. To, że twoje index.jsprzemijanie, nie oznacza, że ​​twoje dist/main.jsprzeminie.
baranskistad
34

Jak wspomniano w innych odpowiedziach, węzeł JS obecnie nie obsługuje importu ES6.

(Na razie czytaj EDYCJA 2)

Włącz import ES6 w węźle js stanowi rozwiązanie tego problemu. Próbowałem tego i zadziałało to dla mnie.

Uruchom polecenie:

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

Teraz musisz utworzyć nowy plik (config.js) i dodać do niego następujący kod.

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

Teraz możesz pisać instrukcje importu bez żadnych błędów.

Mam nadzieję że to pomoże.

EDYTOWAĆ:

Musisz uruchomić nowy plik utworzony za pomocą powyższego kodu. W moim przypadku tak było config.js. Więc muszę uruchomić:

    node config.js

EDYCJA 2:

Podczas eksperymentów znalazłem jedno łatwe rozwiązanie tego problemu.

Utwórz .babelrcplik w katalogu głównym swojego projektu.

Dodaj następujące (i inne potrzebne ustawienia babel, które można dodać w tym pliku):

    {
        "presets": ["env"]
    }

Zainstaluj babel-preset-envza pomocą polecenia npm install babel-preset-env --save, a następnie zainstaluj babel-cliza pomocą polecenianpm install babel-cli -g --save

Teraz przejdź do folderu, w którym znajduje się twój serwer lub plik indeksu i uruchom używając: babel-node fileName.js

Lub możesz uruchomić npm start, dodając następujący kod do swojego package.jsonpliku:

    "scripts": {
        "start": "babel-node src/index.js"
    }
Neerali Acharya
źródło
Jak to zrobić z elektronem? Próbowałem tak: "start": "babel-node electron .", ale bez powodzenia
tpbafk
2
@tpbafk Nie pracowałem na elektronie. Ale znalazłem coś podobnego do problemu javascript - jak ustawić npm start dla aplikacji elektronowej za pomocą „babel-node --presets es2015, stage-3” . Mam nadzieję, że to pomoże
Neerali Acharya
33

Błąd: Błąd składni: nieoczekiwany import tokenu lub Błąd składni: nieoczekiwany eksport tokenu


Rozwiązanie: zmień cały import jako przykład

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

A także zmień export default = foo;namodule.exports = foo;

supritshah1289
źródło
1
Żałuję, że nie wyjaśniłeś nieco więcej części domyślnej eksportu. Mam problem z tą częścią. Import działa świetnie z twoją odpowiedzią.
JoeGalind
Przed moją odpowiedzią jest odpowiedź, która zawiera wyjaśnienie. Ale dla wyjaśnienia Węzeł nie obsługuje składni ES6. Kiedy mówisz Importuj, używasz składni ES6
supritshah1289
22

Jestem zszokowany esm, nie wspomniano. Ten niewielki, ale potężny pakiet pozwala na użycie jednego importlub jednego require.

Zainstaluj ESM w swoim projekcie

$ npm install --save esm

Zaktualizuj skrypt uruchamiania węzła, aby używać esm

node -r esm app.js

esmpo prostu działa. Zmarnowałem TONĘ czasu .mjsi --experimental-modulestylko aby dowiedzieć się, że .mjsplik nie może zaimportować pliku, który używa requirelub module.exports. To był ogromny problem, ale esmpozwala na miksowanie i dopasowywanie, a to po prostu wymyśla ... esmpo prostu działa.

thedanotto
źródło
17

Jeśli nadal nie możesz użyć opcji „importuj”, oto jak sobie z tym poradziłem: po prostu przetłumacz to na wymaganie przyjazne dla węzła. Przykład:

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

Jest taki sam jak:

const parse = require('node-html-parser').parse;
Alberto
źródło
4
nieprawda, jeśli (jak to zapewne jest) używasz exportsłowa kluczowego
Daniel Thompson
@DanielThompson Przepraszam, jeśli to może być nieporozumienie, podaję tylko obejście tej sprawy, jeśli pracujesz bez exportsłowa kluczowego, i tak dziękuję za twoją pomocną notatkę!
Alberto,
Pracuje dla mnie. Dzięki
Ali Azhar,
11

Babel 7 propozycja można dodać zależności deweloperów

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

i dodaj .babelrc w katalogu głównym

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

i dodaj do pliku .js

require("@babel/register")

lub jeśli uruchomisz go w cli, możesz użyć wymaganego hooka jako -r @ babel / register, np.

$node -r @babel/register executeMyFileWithESModules.js
Jason Ashley
źródło
1
Zainstalowanie @ babel / preset-env i dodanie go do .babelrc załatwiło sprawę. W moim przypadku nie ma potrzeby używania wtyczki @ babel / register.
Marcos R
8

jeśli możesz użyć „babel”, spróbuj dodać skrypty kompilacji w package.json (- presets = es2015) jak poniżej. sprawia, że ​​prekompiluje kod importu do es2015

"build": "babel server --out-dir build --presets=es2015 && webpack"
ASTOMUZYKA
źródło
ale czy moje wezwanie, aby npm startnajpierw wykonać „kompilację”, czy najpierw „rozpocząć”? (Początek jest obecnie zdefiniowany:"nodemon src/app.js --exec \"npm run lint && node\"",
pashute
jeśli uruchomię to polecenie cmd, pokazuje błąd serwera nie istnieje
kumaresan_sd
6

Począwszy od wersji 12 Node.js (i jest to prawdopodobnie teraz dość stabilne, ale nadal oznaczone jako „eksperymentalne”), masz kilka opcji korzystania z ESM ( E CMA S cript M odules) w node.js (dla plików, istnieje trzeci sposób sprawdzania ciągów), oto co mówi dokumentacja :

Znacznika --experimental-modulesmożna użyć do włączenia obsługi modułów ECMAScript (modułów ES).

Po włączeniu Node.js będzie traktował następujące elementy jako moduły ES, gdy zostaną przekazane nodejako dane wejściowe lub gdy zostanie do nich odniesienieimport instrukcje w kodzie modułu ES:

  • Pliki z rozszerzeniem .mjs .

  • Pliki z .jsrozszerzeniem lub pliki bez rozszerzeń, gdy najbliższy package.jsonplik nadrzędny zawiera pole najwyższego poziomu "type"o wartości "module".

  • Ciągi przekazane jako argument do --evallub --printlub rurami do nodeurządzeń STDIN, z flagą --input-type=module.

Node.js będzie traktował jako CommonJS wszystkie inne formy wprowadzania danych, takie jak .js pliki, w których najbliższy package.jsonplik nadrzędny nie zawiera "type" pola najwyższego poziomu , lub ciąg znaków bez flagi --input-type. Takie zachowanie ma na celu zachowanie kompatybilności wstecznej. Jednak teraz, gdy Node.js obsługuje zarówno moduły CommonJS, jak i ES, najlepiej jest być jawnym, gdy tylko jest to możliwe. Node.js będzie traktował następujące elementy jako CommonJS, gdy zostaną przekazane nodejako dane wejściowe lub gdy będą się do nich odwoływały importinstrukcje w kodzie modułu ES:

  • Pliki z rozszerzeniem.cjs .

  • Pliki z rozszerzeniem .jsrozszerzeniem lub pliki bez rozszerzeń, gdy najbliższy package.jsonplik nadrzędny zawiera pole najwyższego poziomu "type"o wartości "commonjs".

  • Struny przekazany jako argument --evallub --printlub rurami do nodeurządzeń STDIN, z flagą --input-type=commonjs.

TJ Crowder
źródło
3

Kiedy zaczynałem od express, zawsze chciałem użyć rozwiązania importującego zamiast tego

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

Wiele razy przechodzi przez tę linię: Unfortunately, Node.js doesn't support ES6's import yet.

Teraz, aby pomóc innym, tworzę tutaj dwa nowe rozwiązania

1) esm : -

Genialnie prosta, bezkolumnowa, bezkompletowa ładowarka modułów ECMAScript. niech to zadziała

  yarn add esm / npm install esm

utwórz plik start.js lub użyj przestrzeni nazw

 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

Zmień package.josnścieżkę przejściastart.js

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

2) Babel js : -

Można to podzielić na 2 części

a) Rozwiązanie 1 dzięki timonweb.com

b) Rozwiązanie 2

użyj Babel 6 (starsza wersja babel-preset-stage-3 ^ 6.0 ) utwórz .babelrcplik w folderze głównym

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

Zainstaluj babel-preset-stage-3

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

Zmień pakiet.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"
},

Uruchom serwer

yarn start / npm start

O nie, tworzymy nowy problem

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

Ten błąd pojawia się tylko wtedy, gdy używasz asynchronizacji / oczekiwania w kodzie. Następnie użyj polyfill, który zawiera niestandardowe środowisko uruchomieniowe regeneratora i core-js. dodaj na górzeindex.js

import "babel-polyfill"

Pozwala to na użycie asynchronizacji / oczekiwania

użyj Babel 7

Musisz zaktualizować każdą rzecz w swoim projekcie, zacznijmy od babel 7 .babelrc

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

Niektóre zmiany w pakiecie.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"
....
}

i użyj import "@babel/polyfill"w punkcie początkowym

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!'))

Zastanawiasz się dlaczego start:dev

Poważnie. To dobre pytanie, czy jesteś nowy. Za każdym razem, yarn start:devgdy jesteś dziczy z serwerem startowym, za każdym razem używaj go jako serwera programistycznego. Każda zmiana automatycznie uruchamia serwer ponownie, aby uzyskać więcej informacji o nodemonie

Ashok
źródło
2

W moim przypadku opiekował się .babelrcplikiem i powinien zawierać coś takiego:

{
  "presets": ["es2015-node5", "stage-3"],
  "plugins": []
}
Ghita Tomoiaga
źródło