使用webpack + Vue 开发多页面应用
入口包含一个公用的common.js 和 对应页面的js文件
// common.js
import Vue from 'vue'
import Toast from './plugins/toast'
import Popup from './components/popup'
...
Vue.use(Toast)
Vue.use(Popup)
window.Vue = Vue
// 对应页面的js
import App from './App.vue'
new window.Vue({
template: '<App/>',
components: {App}
}).$mount('#app')
我在App.vue
里调用this.$toast(...)
错误提示: this.$toast不存在
其实我已经Vue.use(Toast)
注册了。
如果我只有一个文件入口能调用this.$toast
我想了想 可能是Vue这对象的问题 我又改了下代码
// common.js
import Toast from './plugins/toast'
import Popup from './components/popup'
...
window.VueInstall = function (Vue) {
Vue.use(Toast)
Vue.use(Popup)
...
}
// 对应页面的js
import Vue from 'vue'
import App from './App.vue'
window.VueInstall(Vue)
new Vue({
template: '<App/>',
components: {App}
}).$mount('#app')
经过了修改,现在能在成功调用this.$toast
,但是却提示我popup这个组件不存在
,因为toast依赖popup组件,toast内部没有单独注册popup这局部组件。App.vue里我写入<popup></popup>
能成功渲染,就只有$toast
这里会提示popup组件不存在
。这是为什么呢?我只有在toast
组件内注册popup
的局部组件才能跑通,why? 我不是注册了全局组件么?
我应该如果解决目前这个问题呢?求解答?
还有一个问题,经过打包出来发现 common.js 和 对应页面.js 的文件内都把vue.js给打包进去了。这该怎么解决呢?
因为项目限制,不能做单页面,只能做多页面。
最后附上多页面的webpack配置
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const config = require('../package.json')
/**
* 获取绝对路径
* @param dir
* @returns {string|*}
*/
function resolve (dir) {
return path.join(process.cwd(), dir)
}
/**
* vue css加载器
* @returns {
* {css: *, scss: *}
* }
*/
function cssLoaders () {
const cssLoader = {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV !== 'development',
sourceMap: false
}
}
function generateLoaders (loader, loaderOptions) {
const loaders = [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: false
})
})
}
if (process.env.NODE_ENV !== 'development') {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
return {
css: generateLoaders(),
scss: generateLoaders('sass')
}
}
const pages = fs.readdirSync(resolve('src/pages'))
module.exports = function ({plugins, htmlPluginOptions}) {
const htmlPlugins = []
const entrys = {
'common': './src/common.js'
}
for (const name of pages) {
const entry = `./src/pages/${name}/index.js`
entrys[name] = [entry]
if (process.env.NODE_ENV === 'development') entrys[name].push('./build/dev-client')
htmlPlugins.push(new HtmlWebpackPlugin(Object.assign({
filename: process.env.NODE_ENV === 'development' ? name + '.html' : resolve(config.id + '/' + name + '.html'),
template: `src/pages/${name}/index.html`,
inject: true,
chunks: ['common', name],
hash: false,
chunksSortMode (a, b) {
return a.id > b.id ? 1 : -1
},
config: {
env: process.env.NODE_ENV
}
}, htmlPluginOptions)))
}
const chunks = Object.values(entrys)
htmlPlugins.push(
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
chunks: chunks,
minChunks: chunks.length
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
chunks: ['common']
})
)
return {
entry: entrys,
output: {
path: resolve(config.id),
filename: 'static/js/[name].js?[hash:7]',
publicPath: `/`,
chunkFilename: 'static/js/[id].[hash].js'
},
resolve: {
extensions: ['.vue', '.js'],
alias: {
'@': resolve('public/src'),
'vue$': 'vue/dist/vue.esm.js'
}
},
devtool: process.env.NODE_ENV !== 'development' ? false : '#cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: cssLoaders()
}
},
{
test: /\.css$/,
use: process.env.NODE_ENV !== 'development' ? ExtractTextPlugin.extract('css-loader') : ['style-loader', 'css-loader']
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src')]
},
{
test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: `[path][name].[ext]?[hash:7]`
}
}
]
},
plugins: htmlPlugins.concat(plugins)
}
}
@NextStack
App.vue:
运行的效果:

popup
全局组件已经注册成功了,上面效果图就说明了。但是toast
里面引用就报错。编译出的html文件:
common.js
是公共js文件,store.js
是对应页面的js文件。common.js
和store.js
里面都引用了.vue
文件,导致2个加入了vue.esm.js
这文件,相当于存在2个Vue
对象,所有我就尝试了我提问时写的2种写法(保证common.js 和 store.js使用的是同一个Vue对象),依然差强人意,需要各位帮忙看看如何解决这问题。当然改为单页面,单文件入口就不会出现以上问题。因项目需求只能做多页面,多入口。
补充:
目前已经解决问题经
NextStack
的提点,使用CommonChunkPlugin
成功解决问题,代码修改如下:代码如上修改,并且webpack设置里移除
common
这个入口。这样只会出现一个vue
对象,然后使用CommonChunkPlugin
把公用代码给提取出来。webpack设置:
被注释掉的代码,是原配置。已经成功解决了,非常感谢
NextStack