nuxt: "SyntaxError: Unexpected token <" on external Vue component

I’ve followed the instructions in the documentation, and I run into the same issue as #380. I’ve done some testing, but can’t nail down what the issue is (the error is exactly the same as the closed issue).

Here is the steps I’ve taken:

  1. vue init nuxt/starter test
  2. cd test
  3. npm install
  4. npm install --save bulma font-awesome node-sass sass-loader vue-bulma-breadcrumb (verified pre-processor instructions from https://nuxtjs.org/faq/pre-processors)
  5. Added { src: 'bulma', lang: 'sass' } as shown in https://nuxtjs.org/api/configuration-css
  6. npm run dev Everything works fine.
  7. Modify default layout to import Breadcrumb from 'vue-bulma-breadcrumb' and added Breadcrumb under components.

At this point, I get the same error as in #380.

Unexpected character ‘@’ (1:0) You may need an appropriate loader to handle this file type. | @import ‘~bulma/sass/utilities/functions’; | @import ‘~bulma/sass/utilities/variables’;

However, if I go and copy the vue file from the module into a component, and load that instead of vue-bulma-breadcrumb it works just fine. Modifying the template to actually reference the Breadcrumb component, it works just fine.

My conclusion is there is something wrong with the configuration that is preventing it from loading from node_modules properly. I’m digging around and exploring for a resolution. In the mean time, I figure someone else may find the fix quicker. This happens with vue-bulma-tooltip as well, but I didn’t explore any other packages.

Is there a step that is being missed or is this a webpack configuration issue?

<div align="right">This feature request is available on Nuxt.js community (#c382)</div>

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

@SharadKumar

Apparently whitelisting by using the module name isn’t enough, you need to use a regex for it to bundle subpaths as well. Here’s wow I fixed that issue with vue-awesome:

const nodeExternals = require('webpack-node-externals');

module.exports = {
   ...
  extend(config, { isServer }) {
    if (isServer) {
      config.externals = [
        nodeExternals({
          whitelist: [/\.(?!(?:js|json)$).{1,5}$/i, /^vue-awesome/]
        })
      ]
    }
  },
  ...
}

Note: the first regex comes from the base nuxt server config.

@Atinux @BigForNothing I face similar issue with vue-awesome:

/node_modules/vue-awesome/icons/globe.js:1
(function (exports, require, module, __filename, __dirname) { import Icon from '../components/Icon.vue'
                                                              ^^^^^^
SyntaxError: Unexpected token import

So taking tip from above and this issue from coosto-hackathon project: https://github.com/esclapes/coosto-hackathon/commit/d055b83cab6a99d3955ffff58c1ae6459bc817d4

I updated my package.json (devDependencies) and nuxt.js:

const nodeExternals = require('webpack-node-externals');

module.exports = {
   ...
   build: {
      vendor: ['vue-awesome']
      ...
   extend(config, ctx) {
      if (ctx.isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      } else {
        config.externals = [ nodeExternals({
          whitelist: ['vue-awesome']
        })]
      }
   }
   ...
}

I started getting this after upgrading to alpha3 from v0.10.7. Again, this works fine on client but fails on server render. What did I miss?

@Atinux I managed to track down the issue on what is causing this. Unless I’m misunderstanding what I’ve gathered from Webpack, it’s actually very simple. All of this should be verifiable using the vue-hackernews-2.0 repo.

In Webpack, it’s recommended to use something similar to this line (line 19 in webpack.server.config.js):

  externals: Object.keys(require('../package.json').dependencies),

According to the Webpack documentation on externals:

The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer’s environment.

Also according to the [resolve.mainFields[(https://webpack.js.org/configuration/resolve/#resolve-mainfields) documentation:

When importing from an npm package, e.g. import * as D3 from “d3”, this option will determine which fields in it’s package.json are checked. The default values will vary based upon the target specified in your webpack configuration.

  • It works on the client-side, because it’s not specified as an external. This mean’s it correctly resolves the file to load by using the appropriate field in package.json. I tested with vue-bulma-breadcrumb, and it’s listed appropriately under the main property.
  • On the server-side, it is listed as an external. So while the external will still find the appropriate file if it’s used without an extension (or the src/Breadcrumb.vue in this case), it’s expecting it to be a loadable module in one of these formats: CommonJS, AMD, global and ES2015 modules. Obviously the single file components are not in any of those formats prior to being ran through vue-loader.
  • Still on the server-side, if a file extension is provided (or the src/Breadcrumb.vue), it will detect that it needs to go through the appropriately loader as determined by module.rules within the Webpack configuration.
  • Since the full name resolution is happening AFTER the tests, there isn’t any loader to run it through. I could be wrong on this part, it could be that it’s skipping the step since it’s expecting it to be pre-compiled. Debugging Webpack is a complete pain.
  • Moving "vue-bulma-breadcrumb": "^1.0.1", from dependencies to devDependencies solves this issue all together.

TL;DR - make sure non-compiled modules like vue-bulma-* (and most likely other non compiled Vue components) are installed using npm install --save-dev so they are saved to devDependencies within package.json.

This is not a nuxt.js issue BTW. I checked several projects that included server rendering for Vue. I didn’t realize vue-hackernews-2.0 used it until today, and that allowed me to exclude any other modifications that differed from the recommendations. However, I would add a note about it to the FAQ because this is one bug that won’t make sense to anyone until they dive in and start to get an understanding of all the different parts of the ecosystem.

To also shame myself, the npm documentation says this under the devDependencies section:

For build steps that are not platform-specific, such as compiling CoffeeScript or other languages to JavaScript, use the prepare script to do this, and make the required package a devDependency.

Although, If I would have done that from the get go, I wouldn’t have got to know Webpack internals better. Thanks again for your patience and help.