Webpack环境下Vue.js代码无法运行的问题求助
我来帮你分析下这个问题,这是模块化开发里很典型的作用域问题,咱们一步步拆解来看:
问题回顾
你写的这段代码在直接引入 vue.js 时能正常运行,但用 Webpack 打包、通过 import Vue from 'vue' 引入后就报错 Uncaught ReferenceError: Vue is not defined,而且控制台还显示 Vue 已经加载成功——这看起来有点矛盾,对吧?
先把你的代码和配置整理下方便参考:
页面代码
<div id="msg"> <h1>{{msg}}</h1> </div>
new Vue({ el: '#msg', data:{ msg:'Hello' } });
依赖配置(package.json)
"devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-preset-es2017": "^6.24.1", "cross-env": "^5.1.3", "css-loader": "^0.28.8", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^1.1.6", "jshint": "^2.9.5", "jshint-loader": "^0.8.4", "lodash": "^4.17.4", "node-sass": "^4.7.2", "sass-loader": "^6.0.6", "style-loader": "^0.19.1", "vue": "^2.5.13", "vue-awesome-swiper": "^3.1.0", "vue-cli": "^2.9.2", "webpack": "^3.10.0" }
Webpack 配置(webpack.config.js)
const webpack = require('webpack'); const paths = require('path'); module.exports = { entry: './js/index.js', output: { filename: 'shop.js', path: paths.resolve(__dirname, 'files/js') }, module: { rules: [ { test:/\*.vue$/, loader: 'vue-loader' }, /* Babel For ES 6*/ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { "presets": ["es2017"] } } }, //Sass Loader { test: /\.s[ac]ss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, //File Loader For Fonts { test: /\.(eot|svg|ttf|woff|woff2)$/, use: [ { loader: 'file-loader', options: { name:`[path][name].[ext]`, } } ] }, //File Loader For IMG { test: /\.(jpg|jpeg|png|gif)$/, use: [ { loader: 'file-loader', options: { name:`[path][name].[ext]`, } } ] } ] } };
核心原因
Webpack 打包的所有模块都是局部作用域的:你在单独 JS 文件里 import 的 Vue,只存在于那个模块的作用域里,不会自动暴露到全局的 window 对象上。而你在 index.html 里写的 new Vue(...) 是在全局作用域执行的,自然找不到局部作用域里的 Vue,所以就报错了。
另外,你的 Webpack 配置里还有个小错误:test:/\*.vue$/ 应该改成 test:/\.vue$/(多了个不必要的星号),这个虽然不是当前报错的直接原因,但之后处理 .vue 文件时会出问题,得先记下来。
解决方案
这里给你几个可行的方案,按推荐程度排序:
1. 把 Vue 初始化代码放到模块里(最推荐)
这是符合模块化开发规范的做法,把所有逻辑都放到 JS 模块中,不要在 index.html 里写全局代码。
修改你的 index.js:
import Vue from 'vue'; // 把Vue初始化代码移到这里 new Vue({ el: '#msg', data:{ msg:'Hello' } });
然后 index.html 只保留 DOM 结构:
<div id="msg"> <h1>{{msg}}</h1> </div>
这样所有代码都在 Webpack 的模块体系内,作用域问题就不存在了。
2. 手动把 Vue 暴露到全局
如果你确实需要在 index.html 里写全局的 Vue 代码,可以在 index.js 里把 Vue 挂载到 window 对象上:
import Vue from 'vue'; window.Vue = Vue; // 将Vue暴露到全局作用域
这样 index.html 里的 new Vue(...) 就能找到全局的 Vue 了。
3. 用 Webpack 插件自动注入全局变量
可以使用 Webpack 的 ProvidePlugin 插件,让它自动把 Vue 注入到所有模块的全局作用域,这样你不用每次 import 也能在模块里使用 Vue。
修改 Webpack 配置:
const webpack = require('webpack'); const paths = require('path'); module.exports = { entry: './js/index.js', output: { filename: 'shop.js', path: paths.resolve(__dirname, 'files/js') }, // 添加plugins配置 plugins: [ new webpack.ProvidePlugin({ Vue: 'vue' }) ], module: { rules: [ // 修正vue-loader的test规则 { test:/\.vue$/, loader: 'vue-loader' }, // ... 其他规则不变 ] } };
这个方案适合很多地方都要用到 Vue、不想每次写 import 的场景,但还是推荐第一种模块化的写法。
最后别忘了修正 Webpack 里 vue-loader 的测试规则,把多余的星号去掉哦!
内容的提问来源于stack exchange,提问作者Siros Fakhri

