nuxt / eslint

Collection of ESLint-related packages for Nuxt
https://eslint.nuxt.com
MIT License
534 stars 65 forks source link

Getting `error Parsing error: Unexpected token .` when using optional chaining #92

Closed davidfilat closed 4 years ago

davidfilat commented 4 years ago

I use optional chaining in one of my .js files and it worked fine until last few days and I cannot figure out what might have caused it to break. Even more strange is the fact the project compiles fine on Heroku.

Module Error (from ./node_modules/eslint-loader/dist/cjs.js):                                 friendly-errors 16:50:32

/Users/davidfilat/GitHub/moldovacrestina-ssr-app/store/resources.js
  36:50  error  Parsing error: Unexpected token .

βœ– 1 problem (1 error, 0 warnings)

                                                                                              friendly-errors 16:50:32
 @ ./.nuxt/store.js 39:22-54 43:4-48:6 43:72-48:5
 @ ./.nuxt/index.js
 @ ./.nuxt/client.js
 @ multi eventsource-polyfill webpack-hot-middleware/client?reload=true&timeout=30000&ansiColors=&overlayStyles=&name=client&path=/__webpack_hmr/client ./.nuxt/client.js

I use Node 14 on my device and here is my package.json the eslint configuration is the default one that comes with nuxt.js.

"dependencies": {
    "@babel/runtime-corejs2": "^7.9.6",
    "@nuxtjs/axios": "^5.10.3",
    "@nuxtjs/device": "^1.2.7",
    "@nuxtjs/dotenv": "^1.4.1",
    "@nuxtjs/localtunnel": "^1.1.3",
    "@nuxtjs/proxy": "^1.3.3",
    "@nuxtjs/pwa": "^3.0.0-beta.20",
    "body-scroll-lock": "^3.0.2",
    "bootstrap": "^4.4.1",
    "bootstrap-vue": "^2.13.0",
    "cross-env": "^7.0.2",
    "dayjs": "^1.8.26",
    "express": "^4.17.1",
    "font-awesome": "^4.7.0",
    "he": "^1.2.0",
    "jquery": "^3.5.0",
    "nuxt": "^2.12.2",
    "plyr": "~3.5.10",
    "popper.js": "1.16.1",
    "vue-plyr": "^6.0.4"
  },
  "devDependencies": {
    "@nuxtjs/color-mode": "^1.0.0",
    "@nuxtjs/eslint-config": "^2.0.2",
    "@nuxtjs/eslint-module": "^1.2.0",
    "@nuxtjs/stylelint-module": "^3.2.2",
    "@vue/test-utils": "^1.0.0-beta.33",
    "babel-jest": "^25.5.1",
    "eslint": "^6.8.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-babel": "^5.3.0",
    "eslint-plugin-nuxt": ">=0.5.2",
    "eslint-plugin-prettier": "^3.1.3",
    "husky": "4.2.5",
    "jest": "^25.5.4",
    "lint-staged": "^10.2.2",
    "nodemon": "^2.0.3",
    "postcss-hexrgba": "^2.0.0",
    "postcss-nested": "^4.2.1",
    "postcss-preset-env": "^6.7.0",
    "postcss-responsive-type": "^1.0.0",
    "postcss-url": "^8.0.0",
    "prettier": "^2.0.5",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2",
    "stylelint": "^13.3.3",
    "stylelint-config-prettier": "^8.0.1",
    "stylelint-config-recommended": "^3.0.0",
    "stylelint-order": "^4.0.0",
    "stylelint-prettier": "^1.1.2",
    "stylelint-scss": "^3.17.1",
    "ts-jest": "^25.4.0",
    "vue-jest": "^4.0.0-0"
  }
manniL commented 4 years ago

Please share your eslint config (.eslinrc) and an example file where that happens.

davidfilat commented 4 years ago

my .eslintrc:

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true,
  },
  extends: [
    'prettier',
    'prettier/vue',
    'plugin:prettier/recommended',
    'plugin:nuxt/recommended',
  ],
  plugins: ['babel', 'prettier'],
  // add your custom rules here
  rules: {
    'nuxt/no-cjs-in-config': 'off',
  },
}

example of file: state/resource.js

import ResourcesService from '@/services/ResourcesService'
import dayjs from 'dayjs'
import 'dayjs/locale/ro'
import { decode } from 'he'
import _ from 'lodash'

export const state = () => ({
  resources: [],
  resource: {},
})

export const mutations = {
  SET_RESOURCES(state, resources) {
    state.resources = resources
  },
  APPEND_PAGE_TO_RESOURCES(state, resources) {
    state.resources = state.resources.concat(resources)
  },
  SET_RESOURCE(state, resource) {
    state.resource.content = resource.content.rendered

    resource.video_meta
      ? (state.resource.resourceType = 'video')
      : (state.resource.resourceType = 'article')

    state.resource.author = resource._embedded.author[0].name

    state.resource.titleRaw = decode(resource.title.rendered)

    state.resource.title = _.split(state.resource.titleRaw, '|', 2)[0]

    state.resource.typeClass = 'resource-card--' + state.resourceType

    state.resource.date = dayjs(resource.date_gmt).format('D MMMM YYYY')

    state.resource.videoID = resource.video_meta?._ayvpp_video

    state.resource.slug = resource.slug
  },
}

export const actions = {
  async fetchResources({ commit }) {
    const response = await ResourcesService.getResources()
    commit('SET_RESOURCES', response.data)
  },
  async fetchNextResourcesPage({ commit }, payload) {
    const response = await ResourcesService.getResources(payload.pageNr, 12)
    commit('APPEND_PAGE_TO_RESOURCES', response.data)
  },
  async fetchResource({ commit }, slug) {
    const response = await ResourcesService.getResource(slug)
    commit('SET_RESOURCE', response.data[0])
  },
}
manniL commented 4 years ago

@davidfilat Please check https://github.com/nuxt/eslint-config#full-example and add the correct parser (babel-eslint). This might resolve the issue

davidfilat commented 4 years ago

I did as instructed and the error disappeared from the Eslint report, but webpack still reports the error at runtime:

CleanShot 2020-05-03 at 13 51 19@2x

Here is the updated .eslintrc:

module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
    sourceType: 'module',
  },
  env: {
    browser: true,
    node: true,
  },
  extends: [
    '@nuxtjs',
    'prettier',
    'prettier/vue',
  ],
  plugins: [
    'prettier'],
  rules: {
    'nuxt/no-cjs-in-config': 'off',
    'camelcase': 'off'
  },
}
davidfilat commented 4 years ago

@manniL I've gone forward to test my theory that it has something to do with the Node version and I've created a docker container using Node 12-lts and everything works fine, but when I tried the same configuration but with Node 13 and 14, I got the same error.

Here is the docker-compose.yml and Dockerfile that worked fine:

version: '3.7'

services:
  nuxt:
    build: ./
    volumes:
      - .:/usr/src/app
    working_dir: /usr/src/app
    ports:
      - '3000:3000'
    command: 'yarn run dev'
    environment:
      HOST: 0.0.0.0
FROM node:lts
ENV APP_ROOT /usr/src/app
RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}
ADD . ${APP_ROOT}
RUN yarn install
davidfilat commented 4 years ago

Also, I've installed Node 12.16.3 lts using NVM and deleted .node_modules and yarn.lock. After reinstalling the dependencies everything works fine.

davidfilat commented 4 years ago

Are there any updates with this issues?

manniL commented 4 years ago

This is not an eslint-config issue anymore then. Updating deps could help (so the latest babel preset with optional chaining is included).

~BTW: Please be aware that Node.js itself doesn't support optional chaining right now without a flag (source).~

tomscytale commented 4 years ago

actually node supports optional chaining since version 14.0

 $ node --version
v14.2.0
 $ echo "let foo = {a: {c: 3}, b: {}}; console.log('a: ' + foo?.a?.c + ', c: ' + foo?.b?.c)" | node -
a: 3, c: undefined

The compatibility chart at https://node.green/#ES2020-features-optional-chaining-operator----- is broken and out of date.

manniL commented 4 years ago

Ah, good to know πŸ‘πŸ»

davidfilat commented 4 years ago

@manniL, I've updated all dependencies and still it doesn't work...

dschreij commented 4 years ago

I have the same problem! Suddenly optional chaining and null coalescence stopped working with these error messages. I didn't change anything at all, except for running a brew upgrade (I'm on a mac), so I indeed think this has something to do with underlying processes.

davidfilat commented 4 years ago

@dschreij Though the team couldn't provide any clarifying explanation, I'm still pretty sure it's caused by the upgrade to Node 14. Here is the solution to solve the problem on my project:

  1. Add the following dependencies to your package.json:
    "devDependencies: {
        ...
        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1",
        "@babel/plugin-proposal-optional-chaining": "^7.10.1",
        "babel-eslint": "^10.1.0",
        "eslint-plugin-babel": "^5.3.0",
    },

Modify your .babelrc file to look like this:

{
  "env": {
    "test": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  },
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator",
    "@babel/plugin-proposal-optional-chaining"
  ]
}
  1. Modify your eslintrc.js:
    
    module.exports = {
    root: true,
    parserOptions: {
    parser: 'babel-eslint',
    sourceType: 'module',
    },
    env: {
    browser: true,
    node: true,
    },
    extends: [
    '@nuxtjs',
    ],
    plugins: ['babel'],
    rules: {},
    }
dschreij commented 4 years ago

Hi David. Thanks for your suggestions. Be aware though that nuxt according to its docs ignores the .babelrc file and only honors babel settings through its own config file.

davidfilat commented 4 years ago

Thank you @dschreij, but as long as it solves the problem - I'm cool! πŸ˜„

dschreij commented 4 years ago

I am furthermore wondering if this issue may be related to https://github.com/nuxt/typescript/issues/248 although I don't use typescript in my project...

I tried another nuxt project with similar dependencies and the same node version and that did work with the optional chaining and null coalescence operator, so I am not entirely sure it's the node version alone.

davidfilat commented 4 years ago

I don't use TypeScript either in my project. I say it's connected to the Node version, because it runs smooth with Node 12 on my machine (with NVM) and on Heroku too.