Justineo / vue-awesome

Awesome SVG icon component for Vue.js, built-in with Font Awesome icons.
https://justineo.github.io/vue-awesome/demo/
MIT License
2.43k stars 211 forks source link

Uncaught SyntaxError: Unexpected token import #7

Closed ryandeussing closed 8 years ago

ryandeussing commented 8 years ago

First, I installed: npm install vue-awesome --save-dev

Then I added the following lines to main.js, based on the readme and example:


import Icon from 'vue-awesome/src/components/Icon.vue';
Vue.component('icon', Icon);

I get this error in the browser console: > Uncaught SyntaxError: Unexpected token import Icon.vue?7cbb:36

Am I doing something incorrect? Thx!

Justineo commented 8 years ago

If you are importing from src directly you have to use webpack + vue-loader + babel. You can use other approaches if you don't want to setup that environment.

ryandeussing commented 8 years ago

Actually I am, I'm using the webpack template: https://github.com/vuejs-templates/webpack

Justineo commented 8 years ago

Have you configured .babelrc in your project?

fatbrain commented 8 years ago

I had similar (if not the same) problem, I'm using webpack + vue-loader + babel. I have a .babelrc but without add-module-exports plugin, but adding that to my own .babelrc didn't do me any good. I ended up importing the dist instead, worked like a charm.

import * as Icon from 'vue-awesome'

Cheers, fatbrain

WalterZou commented 8 years ago

I also had similar problem. I have already added add-module-exports to .babelrc, but it still came out with error Icon.vue?7cbb:36 Uncaught SyntaxError: Unexpected token import

Justineo commented 8 years ago

It seemed to be not working correctly with Vue 2.0's webpack template. I'll look into this guys.

Pistos commented 8 years ago

import * as Icon from 'vue-awesome'

^ this did the trick for me, along with

components: {
  'icon': Icon,
}

in the .vue file. (I am using the webpack template.)

Justineo commented 8 years ago

@Pistos Yes that will work but you are including the whole Font-Awesome icon pack into your code. The original thought of importing directly from src is to only include the icons you actually need.

hefengxian commented 8 years ago

i got the same problem too

Pistos commented 8 years ago

@Justineo Sure, but I just need something to get going in development while you work out the real fix. :) Is there a workaround for only including specific icons?

Justineo commented 8 years ago

This issue turns out to be caused by config files included in the package (which I forgot to remove upon publish.) and I think it might still be an issue for those who install from bower.

vue-awesome@2.0.2 should fix this one.

Pistos commented 8 years ago

Sorry, I still get this error with 2.0.2. What's the syntax to use one single icon? Because the example in the README still gives me this error.

Pistos commented 8 years ago

Sorry, actually, the error is:

util.js?8f12:34 Uncaught SyntaxError: Unexpected token export

And the source trace for the error is:

  const formatLocation = str => {
    if (str === 'anonymous component') {
      str += ` - use the "name" option for better debugging messages.`
    }
    return `(found in ${str})`
  }
}

export { warn }
Justineo commented 8 years ago

Sorry, I forgot to mention one more thing. Vue's webpack project template has excluded node_modules from files to be transpiled by Babel so you have to exclude vue-awesome from the exclude pattern in build/webpack.base.conf.js like this: exclude: /node_modules(?![\\/]vue-awesome[\\/])/.

Pistos commented 8 years ago

@Justineo I still can't get it to work without the workaround I mentioned above. Could you please provide a minimal example for using this with webpack and ES6?

Justineo commented 8 years ago

@Pistos

  1. Use vue init webpack to start from scratch.
  2. After finished what vue-cli ask you to do, run npm i vue-awesome.
  3. Modify exclude config in build/webpack.base.conf.js as I mentioned earlier.
  4. Import Vue-Awesome.

    eg. in src/App.vue:

    // import the source version of the component
    import Icon from 'vue-awesome/components/Icon'
    
    // pick your icons
    import 'vue-awesome/icons/flag'
    
    export default {
     name: 'app',
     components: {
       Hello,
       Icon // register local component here
     }
    }

    Add components into the template:

    <icon name="flag"></icon>
  5. Run npm run dev and it should be working now.
Justineo commented 7 years ago

@Pistos Does the instructions above work for you?

Pistos commented 7 years ago

@Justineo I haven't tried yet, sorry. I will get back to you when I do.

Pistos commented 7 years ago

The minimal example doesn't work, though for a different reason:

% npm run dev

> icon-test@1.0.0 dev /home/pistos/tmp/x
> node build/dev-server.js

Listening at http://localhost:8080

webpack: wait until bundle finished: /__webpack_hmr
webpack: wait until bundle finished: /index.html
[Vue warn]: Vue is a constructor and should be called with the `new` keyword 
webpack built 4469ccf72345a82f8420 in 36435ms
Hash: 4469ccf72345a82f8420
Version: webpack 1.13.3
Time: 36435ms
 Asset     Size  Chunks       Chunk Names
app.js  1.43 MB       0       app

ERROR in ./~/vue-awesome/components/Icon.vue
Module build failed: TypeError: this._init is not a function
    at Object.Vue$2 (/home/pistos/tmp/x/node_modules/vue-awesome/node_modules/vue/dist/vue.common.js:2594:8)
 @ ./~/vue-awesome/icons/flag.js 3:12-45
Child html-webpack-plugin for "index.html":
         Asset     Size  Chunks       Chunk Names
    index.html  1.46 MB       0       
webpack: bundle is now VALID.

My App.vue is:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <icon name="flag"></icon>
    <hello></hello>
  </div>
</template>

<script>
import Hello from './components/Hello'

// import the source version of the component
import Icon from 'vue-awesome/components/Icon'

// pick your icons
import 'vue-awesome/icons/flag'

export default {
  name: 'app',
  components: {
    Hello,
    Icon // register local component here
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

My webpack.base.conf.js is:

var path = require('path')
var config = require('../config')
var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../')

var env = process.env.NODE_ENV
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the
// various preprocessor loaders added to vue-loader at the end of this file
var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
var useCssSourceMap = cssSourceMapDev || cssSourceMapProd

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
    filename: '[name].js'
  },
  resolve: {
    extensions: ['', '.js', '.vue'],
    fallback: [path.join(__dirname, '../node_modules')],
    alias: {
      'vue$': 'vue/dist/vue',
      'src': path.resolve(__dirname, '../src'),
      'assets': path.resolve(__dirname, '../src/assets'),
      'components': path.resolve(__dirname, '../src/components')
    }
  },
  resolveLoader: {
    fallback: [path.join(__dirname, '../node_modules')]
  },
  module: {
    preLoaders: [
      {
        test: /\.vue$/,
        loader: 'eslint',
        include: projectRoot,
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        loader: 'eslint',
        include: projectRoot,
        exclude: /node_modules/
      }
    ],
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue'
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: projectRoot,
        exclude: /node_modules(?![\\/]vue-awesome[\\/])/
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  eslint: {
    formatter: require('eslint-friendly-formatter')
  },
  vue: {
    loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
    postcss: [
      require('autoprefixer')({
        browsers: ['last 2 versions']
      })
    ]
  }
}
cenkai88 commented 7 years ago

@Pistos +1 i have the same problem....

cenkai88 commented 7 years ago

@Pistos pls check ur webpack.base.conf.js and change the loaders for .vue to 'vue-loader' instead of 'vue'

loaders: [
  {
    test: /\.vue$/,
    loader: 'vue-loader'
  }, ..
```.
romoo commented 7 years ago

Same problem here.

Uncaught SyntaxError: Unexpected token export(…)    util.js?12f5:34 
Justineo commented 7 years ago

@romoo have you tried the solution above?

romoo commented 7 years ago

@Justineo This is cnpm's problem. Package folder have been changed, so exclude: /node_modules(?![\\/]vue-awesome[\\/])/ does not work.

vue-awesome -> .npminstall/vue-awesome/2.0.3/vue-awesome

cenkai88 commented 7 years ago

@romoo
pls check the loader for '.vue' is vue-loader, not vue

tonypee commented 7 years ago

I just had to go searching to find how to make this work too - the above instructions worked.

It would definitely be better to have a precompiled version working (in the dist/) - which i'm not sure why that currently doesnt work, eg:

import Icon from 'vue-awesome' import 'vue-awesome/icons/flag'

currently that barfs with: ERROR in ./~/vue-awesome/dist/vue-awesome.js Module build failed: SyntaxError: 'with' in strict mode (16:30907)

Ill stick with the compiled approach atm - but it seems weird to have to change my excludes and compile a lib manually - maybe there are good reasons for it tho

Justineo commented 7 years ago

@tonypee You mean you'd like to let each icon have its own compiled version?

tonypee commented 7 years ago

could the icons be json, as to allow them to work in es5?

.. or why arnt they a font? ;)

tonypee commented 7 years ago

or instead on json.. svg files

Justineo commented 7 years ago

@tonypee

Icons are not provided from a font or JSON/SVG files because we are using inline SVG to deliver them (GitHub is currently using this technique). I put them in separate JavaScript modules so that users can import any icon only when they need it. The all-in-one bundle is distributed as an ES5 module so users can just require('vue-awesome') to include the whole bundle of all icons. If they want reduce bundle size by only importing those icons they actually need they can use the source version of the component (which is written in ES Next) and this needs transpiling.

tonypee commented 7 years ago

Okay, so staying with inline-css, cant you can still do inline css with the data being external, in a json file - the import/register would just be done in the project:

import Icon from 'vue-awesome'
import flag from 'vue-awesome/icons/flag'  (this is json)

Icon.register(flag)

example json:

{
"arrow-circle-o-right":{"width":1536,"height":1792,"d":"M1152 896q0 14-9"},
}

So, the only difference is that the flag file is json, so it doesnt need to be compiled, and therefore you have to call Icon.register yourself - which will store the inline svg data in a map, to be used by the system as inline svg

for all of them (just more icons in the json)

maybe

eg: import all from 'vue-awesome/icons/all'
{
"arrow-circle-o-right":{"width":1536,"height":1792,"d":"M1152 896q0 14-9"},
"arrow-circle-o-left":{"width":1536,"height":1792,"d":"M1152 896q0 14-9"},
}
Justineo commented 7 years ago

You cannot just import a JSON file like an ES module like that. It should be:

module.exports = {
  "arrow-circle-o-right": {"width": 1536, "height": 1792, "d": "M1152 896q0 14-9"}
}

And providing icons as self-registering modules makes it easier to import them.

I'm not sure why modules in node_modules should all be ES5 compatible.

tonypee commented 7 years ago

I guess it is a matter of choice, whether you think you should export to es5 or consume es6 directly, i think it is more common to still target es5 from what i see tho.

I just found that it was confusing (maybe the readme could be more explicit), in that i incorrectly assumed that i could import from 'vue-awesome', with closer inspection, bugsearching (how im here), and changing babel, yes es6 works too, but it took a bit of time. It is more common to expect that you just import from the root module, and i guess i just skim readme's (probably a bad habit, but maybe a common habit - looking at other people's issues)

So the only benefit of exporting as you states above is that there is one usage:

import Icon from 'vue-awesome'

import flag from 'vue-awesome/icons/flag' // import individually Icon.register(flag)

import all from 'vue-awesome/icons' // import all Icon.register(all)

thanks for the great library anyway! ill be using it whether this happens or not

Justineo commented 7 years ago

@tonypee

You can import from the root module and it is already ES5 but just with all icons bundled. I'd rather provide ES Next source because users can use tools that understands ES Next (eg. Rollup.js) to further optimize the result bundle. Many users using Vue are already using transpilers so I assume it will not be a big problem. Maybe it can be elaborated better in the project readme.

tonypee commented 7 years ago

I do realize all that.. Just saying how it could be easier - as obviously we are on an issue here, that people have

On Thu, Dec 22, 2016 at 4:27 PM GU Yiling notifications@github.com wrote:

@tonypee https://github.com/tonypee

You can import from the root module and it is already ES5 but just with all icons bundled. I'd rather provide ES Next source because users can use tools that understands ES Next (eg. Rollup.js) to further optimize the result bundle. Many users using Vue are already using transpilers so I assume it will not be a big problem. Maybe it can be elaborated better in the project readme.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Justineo/vue-awesome/issues/7#issuecomment-268721819, or mute the thread https://github.com/notifications/unsubscribe-auth/AC8aNRoRbFpf9QtCF39CDx1YusuxHSmPks5rKgoZgaJpZM4KS9LO .

cenkai88 commented 7 years ago

@tonypee you can also try this https://github.com/cenkai88/vue-svg-icon, no awesome font preinstalled, purely custom svg icons...

brianbancroft commented 7 years ago

Hi, I just wanted to say that I'm also running into the same symptom when attempting to run vue-awesome after a vue-cli install with vue-router. I've attempted all the fixes listed on this issue suggested by the authour:

feryardiant commented 7 years ago

Hi @Justineo, I just got same problem here with laravel-mix, which is I don't have any idea to add such a specific webpack config in laravel-mix as you describe in your readme, because I newbie.

I do realize that the only thing causing problem is your utils.js file, which is only called once here. I curious to know why you use your own custom warning function instead of using built-in javascript function or just thrown an Error instead?

Last one, I manage to build my project without additional configuration just by replacing line 83 with throw new Error(...).

Regards 😁

Justineo commented 7 years ago

Actually warn in util.js is directly ported from Vue.js's source to provide better warning message during development. It's not resolved by vue-loader so it's required to have Babel transpile this piece of ES Next code. Of course you can replace it with the native console.warn or throwing errors. But maybe you can look for how laravel-mix handles Webpack config and modify babel-loader's config as mentioned in the README.

feryardiant commented 7 years ago

Finally I managed to make it works in my build using this additional config.

mix.webpackConfig({
    resolve: {
        alias: {
            components: '../../components'
        }
    },
+    module: {
+        rules: [{
+            test: /\.jsx?$/,
+            exclude: /(node_modules(?![\\/]vue-awesome[\\/])|bower_components)/,
+            loader: 'babel-loader' + mix.Mix.babelConfig()
+        }]
    }
});

Thank you, you've give me an hour extra work to discover. Sorry, but I have to say your 1 line of code cause me to add 6 lines of additional config to make it works.

Justineo commented 7 years ago

Actually you can fork the project into your own repository and customize it as you like.

feryardiant commented 7 years ago

Forking a package & only modifying 1 line of it's original code is completely wasting of time, IMO.

As you said earlier "it provide better warning message during development", yes it is! but always fails on production build, seriously?

Justineo commented 7 years ago

You can use the compiled version if you don't want to bother about build configurations. Sure I can move util.js into the component file itself to let vue-loader to transpile the code. This seem to cause much trouble to configure babel-loader.

feryardiant commented 7 years ago

Sure I can move util.js into the component file itself to let vue-loader to transpile the code

Really love to hear that, thank you for consideration.

hellozhangran commented 7 years ago

@Justineo I have the same question : 'Uncaught SyntaxError: Unexpected token export'

image

image

Pistos commented 7 years ago

I just wanted to mention here that, with a newer, separate project, the installation and usage instructions in the vue-awesome readme Just Worked for

    "vue": "^2.2.6",
    "vue-awesome": "^2.3.1",
    "vue-loader": "^11.3.4",
SteveCruise commented 7 years ago

I didn't solve this.

/root/WebstormProjects/PHC/vue-server/node_modules/vue-awesome/icons/index.js:1
(function (exports, require, module, __filename, __dirname) { import './500px'
                                                              ^^^^^^

SyntaxError: Unexpected token import

my webpack configure file

rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: vueConfig
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                // include: ['node_modules/vue-awesome'],
                exclude: /node_modules(?![\\/]vue-awesome[\\/])/
            },
...

I use "vue-awesome": "^2.3.1" and I use vue ssr.

jonnyparris commented 7 years ago

+1 SyntaxError: Unexpected token import using Nuxt for SSR with basically the same webpack config

massada commented 7 years ago

@jonnyparris

Nuxt's server webpack config excludes all external modules from being transpiled in the server build. You need to whitelist vue-awesome (and it's subpaths). Here's how I fixed it for SSR:

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.

Justineo commented 7 years ago

@massada

Thanks for the solution. It seems that I should add a "Usage with Nuxt.js" section in the readme.