yuche / vue-strap

Bootstrap components built with Vue.js
http://yuche.github.io/vue-strap/
MIT License
4.72k stars 933 forks source link

Webpack Problems #52

Closed ChromoX closed 8 years ago

ChromoX commented 8 years ago

The following error occurs when trying to import a module from vue-strap.

./~/vue-strap/src/main.js
Module parse failed: /Users/Jeffrey/Sites/AHUD/node_modules/vue-strap/src/main.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| export alert from './Alert.vue'
| export carousel from './Carousel.vue'
| export slider from './Slider.vue'
 @ ./~/babel-loader!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Planning/Goals.vue 7:16-36

webpack.config.js

var webpack = require('webpack')
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var vue = require('vue-loader')
var path = require('path')
var nodeRoot = path.join(__dirname, 'node_modules')

module.exports = {
  entry: './src/main.js',
  output: {
    path: './dist',
    publicPath: 'dist/',
    filename: 'build.js'
  },
  module: {
    loaders: [
      {test: /\.vue$/, loader: 'vue'},
      {test: /\.js$/, exclude: /node_modules|main.js|vue\/src|vue-router\/|vue-loader\/|vue-hot-reload-api\//, include: /node_modules\/vue-strap\/src/, loader: 'babel'},
      {test: /\.(png|jpg|gif)$/, loader: 'file?name=[name].[ext]?[hash]'}
    ]
  },
  // example: if you wish to apply custom babel options
  // instead of using vue-loader's default:
  babel: {
    presets: ['es2015', 'stage-0'],
    plugins: ['transform-runtime'],
    cacheDirectory: true
  },
  // Vue Settings
  vue: {
    loaders: {
      // css: ExtractTextPlugin.extract("css"),
      // stylus: ExtractTextPlugin.extract("css!stylus"),
      // js: 'babel?optional[]=runtime&loose=all'
    }
  }
}

Package.json

{
    "name": "ahud",
    "version": "0.1.0",
    "description": "AHUD",
    "main": "index.js",
    "scripts": {
        "dev": "webpack-dev-server --inline --hot --quiet",
        "build": "export NODE_ENV=production webpack --progress --hide-modules"
    },
    "dependencies": {
        "vue": "^1.0.0",
        "vue-strap": "^0.1.2",
        "vue-router": "^0.7.5",
        "vue-resource": "^0.1.16",
        "d3": "^3.5.6",
        "nvd3": "^1.8.1",
        "plotly.js": "^1.0.0"
    },
    "devDependencies": {
        "babel-core": "^6.1.2",
        "babel-loader": "^6.1.0",
        "babel-plugin-transform-runtime": "^6.1.2",
        "babel-preset-es2015": "^6.1.2",
        "babel-preset-stage-0": "^6.1.2",
        "babel-runtime": "^6.0.14",
        "css-loader": "^0.21.0",
        "extract-text-webpack-plugin": "^0.8.2",
        "file-loader": "^0.8.4",
        "jade": "^1.11.0",
        "style-loader": "^0.13.0",
        "stylus-loader": "^1.4.0",
        "template-html-loader": "0.0.3",
        "vue-hot-reload-api": "^1.2.0",
        "vue-html-loader": "^1.0.0",
        "vue-loader": "^7.0.0",
        "webpack": "^1.12.3",
        "webpack-dev-server": "^1.12.0"
    }
}

I've tried all the tricks from other threads talking about this.

amanpatel commented 8 years ago

That error generally means that babel is not getting to load the main.js file. (Line 1 of that main.js is just an import statement).

Take a look at this line:

{
  test: /\.js$/, 
  exclude: /node_modules|main.js|vue\/src|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
  include: /node_modules\/vue-strap\/src/,
  loader: 'babel'
},

Just make sure you are including and excluding stuff correctly for babel loader.

ChromoX commented 8 years ago

Thanks for the response amanpatel. I've tried a much simpler version, without any luck. I decided to use your exact line instead of mine. I ended up with the following error:

Error: Cannot find module "url"
amanpatel commented 8 years ago

Try again by replacing the .js loader link in your webpack config file to:

      {test: /\.js$/, exclude: /node_modules|vue\/src|vue-router\/|vue-loader\/|vue-hot-reload-api\//, include: /node_modules\/vue-strap\/src/, loader: 'babel'},

Not sure if it will fix it, but atleast you might get further.

ChromoX commented 8 years ago

amanpatel: Taking the main.js out removes the error:

Error: Cannot find module "url"

But the error from the first comment in this thread comes back.

Module parse failed: /Users/Jeffrey/Sites/AHUD/node_modules/vue-strap/src/main.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
yuche commented 8 years ago

Try remove include option like this:

      {
        test: /\.js$/,
        exclude: /node_modules|vue\/src|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
        loader: 'babel'
      },
ChromoX commented 8 years ago

So this is driving me insane! You can replicate this problem by executing these commands:

git clone https://github.com/vuejs/vue-loader-example.git
npm install
npm install vue-strap

Then add the following to the loaders section in webpack.config.js:

      {
        test: /\.js$/,
        exclude: /node_modules|vue\/src|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
        loader: 'babel'
      },

Then finally adding the following to src/components/counter.vue:

import { accordion } from 'vue-strap'
ablipan commented 8 years ago

@yuche I'm crazy about the problem too. my loader

{
      test: /\.js$/,
      include: [
        path.resolve(nodeRoot, 'vue-strap/src')
      ],
      loader: 'babel'
}

my login.vue

import { alert } from 'vue-strap'
export default {
  data() {
    return {
      rememberMe: false
    }
  },
  ready(){
    console.log(alert);
  },
  // ...
}

and the alert is undefined

amanpatel commented 8 years ago

Ok, I tried to recreate this on my environment, and was able to figure out a partial solution. Again the main reason you are seeing the syntax error on main.js is that the babel loader is not being able to apply ES2015 transforms to main.js (which is why it croaks at the import statement).

I was able to partially solve this by using the following webpackconfig file:

var webpack = require('webpack')

module.exports = {
  entry: './src/main.js',
  output: {
    path: './dist',
    publicPath: 'dist/',
    filename: 'build.js'
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue'
      },
      {
                test: /\.js$/,
                include: /node_modules\/vue-strap/,
                loader: 'babel',
                query: {
                    presets: [ 'es2015','stage-0']
                }
      },
      {
        // edit this for additional asset file types
        test: /\.(png|jpg|gif)$/,
        loader: 'file?name=[name].[ext]?[hash]'
      }
    ]
  }
}

if (process.env.NODE_ENV === 'production') {
  module.exports.plugins = [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.optimize.OccurenceOrderPlugin()
  ]
} else {
  module.exports.devtool = '#source-map'
}

The big change here is the include statement (and removal of exclude).

I don't use the hot-loader in my day to day development, so please regard this solution as 'experimental' (the entire webpack hot reload is experimental stage anyway).

Closing this issue for now.

ablipan commented 8 years ago

@amanpatel I've tried your solution, webpack can build normally, but the alert import by import { alert } from 'vue-strap' is still undefined.

ablipan commented 8 years ago

@amanpatel @yuche I'm using the temporary import method import alert from 'vue-strap/src/Alert.vue' now.

amanpatel commented 8 years ago

Using this: import {alert} from 'vue-strap'; worked for me. Are you using the entire webpack.config.js as I posted?

Here's my counter.vue (from @ChromoX vue-loader-example script).

<template>
  <div>
    <h1>I am a Counter Component. Edit me in dev mode.</h1>
    <p>Current count: {{count}}</p>

    <alert type="success" >
  <strong>Well Done!</strong>
  You successfully read this important alert message.
</alert>

  </div>
</template>

<script>
import {alert} from 'vue-strap';

export default {
    components: {
        alert: alert
    },
  data () {
    return { count: 0 }
  },

  ready () {
    this.handle = setInterval(() => {
      this.count++
    }, 1000)
  },

  destroyed () {
    clearInterval(this.handle)
  }
}
</script>