使用webpack + Vue 開發(fā)多頁面應(yīng)用
入口包含一個公用的common.js 和 對應(yīng)頁面的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
// 對應(yīng)頁面的js
import App from './App.vue'
new window.Vue({
template: '<App/>',
components: {App}
}).$mount('#app')
我在App.vue里調(diào)用this.$toast(...) 錯誤提示: this.$toast不存在 其實我已經(jīng)Vue.use(Toast)注冊了。
如果我只有一個文件入口能調(diào)用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)
...
}
// 對應(yīng)頁面的js
import Vue from 'vue'
import App from './App.vue'
window.VueInstall(Vue)
new Vue({
template: '<App/>',
components: {App}
}).$mount('#app')
經(jīng)過了修改,現(xiàn)在能在成功調(diào)用this.$toast,但是卻提示我popup這個組件不存在,因為toast依賴popup組件,toast內(nèi)部沒有單獨注冊popup這局部組件。App.vue里我寫入<popup></popup>能成功渲染,就只有$toast這里會提示popup組件不存在。這是為什么呢?我只有在toast組件內(nèi)注冊popup的局部組件才能跑通,why? 我不是注冊了全局組件么?
我應(yīng)該如果解決目前這個問題呢?求解答?
還有一個問題,經(jīng)過打包出來發(fā)現(xiàn) common.js 和 對應(yīng)頁面.js 的文件內(nèi)都把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)
}
}App.vue:
<template>
<div>
<popup v-model="visible">
我是popup組件
</popup>
</div>
</template>
<script>
export default {
data () {
return {
visible: true
}
},
created () {
this.$toast('啦啦啦!我是賣報的小當家。')
}
}
</script>
<style lang="scss" rel="stylesheet/scss" type="text/scss">
</style>
運行的效果:
popup全局組件已經(jīng)注冊成功了,上面效果圖就說明了。但是toast里面引用就報錯。
編譯出的html文件:
...
<script type="text/javascript" src="/static/js/common.js?f56345f"></script>
<script type="text/javascript" src="/static/js/store.js?f56345f"></script>
...
common.js是公共js文件,store.js是對應(yīng)頁面的js文件。common.js 和 store.js里面都引用了.vue文件,導致2個加入了vue.esm.js這文件,相當于存在2個Vue對象,所有我就嘗試了我提問時寫的2種寫法(保證common.js 和 store.js使用的是同一個Vue對象),依然差強人意,需要各位幫忙看看如何解決這問題。
當然改為單頁面,單文件入口就不會出現(xiàn)以上問題。因項目需求只能做多頁面,多入口。
補充:
目前已經(jīng)解決問題經(jīng)NextStack的提點,使用CommonChunkPlugin成功解決問題,代碼修改如下:
// common.js
import Toast from './plugins/toast'
import Popup from './components/popup'
export default function (Vue) {
Vue.use(Toast)
Vue.use(Popup)
}
// 對應(yīng)頁面的js
import Vue from 'vue'
import install from '../../common'
import App from './App.vue'
install(Vue)
new Vue({
template: '<App/>',
components: {App}
}).$mount('#app')
代碼如上修改,并且webpack設(shè)置里移除common這個入口。這樣只會出現(xiàn)一個vue對象,然后使用CommonChunkPlugin把公用代碼給提取出來。
webpack設(shè)置:
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],
chunks: ['common.js', 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)
plugins: htmlPlugins.concat(plugins).concat([new webpack.optimize.CommonsChunkPlugin('common.js')])
}
}
被注釋掉的代碼,是原配置。已經(jīng)成功解決了,非常感謝NextStack
不如直接用 vue 命令行的 webpack 項目模板創(chuàng)建項目,然后稍微修改一下 webapck 的配置文件
北大青鳥APTECH成立于1999年。依托北京大學優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
達內(nèi)教育集團成立于2002年,是一家由留學海歸創(chuàng)辦的高端職業(yè)教育培訓機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學校辦產(chǎn)業(yè)為響應(yīng)國家深化產(chǎn)教融合/校企合作的政策,積極推進“中國制造2025”,實現(xiàn)中華民族偉大復興的升級產(chǎn)業(yè)鏈。利用北京大學優(yōu)質(zhì)教育資源及背
博為峰,中國職業(yè)人才培訓領(lǐng)域的先行者
曾工作于聯(lián)想擔任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍懿科技有限責任公司從事總經(jīng)理職務(wù)負責iOS教學及管理工作。
浪潮集團項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術(shù)功底深厚。 授課風格 授課風格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。