當咱們基於vue開發單個項目時,咱們會init一個vue-cli,但當咱們想在其餘項目裏共用這套模板時,就須要從新init一個,或者clone過來,這很是不方便,並且當多人開發時,咱們但願全部的開發代碼都在一個git目錄下,這時就有了對webpack進行配置的需求,當有些頁面須要多入口時,咱們又產生了對多入口配置的需求,這裏提供一種配置方案,但願能幫助到有須要的人,廢話很少說,咱們開始吧!javascript
咱們經過vue init webpack demo 生成的文件目錄是這樣的css
要改多入口,首先改造一下webpack.base.conf.js
中的context
和entry
。html
context:基礎目錄,絕對路徑,用於從配置中解析入口起點(entry point)和 loader。vue
entry:起點或是應用程序的起點入口。從這個起點開始,應用程序啓動執行。java
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
};
複製代碼
若是項目只有一個入口,那麼直接在這裏改entry就能夠了,但通常咱們都是多個項目在放一個目錄裏,因此要提取出來context和entry。webpack
const paths = require('./paths')
const rootPath = paths.rootPath
module.exports = {
context: rootPath
entry: {
app: utils.getEntry(),
},
};
複製代碼
_config.js
和paths.js
_config.js
,用於設置當前啓動項目,並將這個文件添加到.gitignore中,由於之後多人開發都是在本地修改項目地址。git
'use strict'
module.exports = {
appName: 'mobile',
projectName: 'demo'
}
複製代碼
這裏設計2個目錄,appName是src下的一級目錄,projectName是appName下的二級目錄,目的在於方便拓展,好比公司的項目分爲pc項目和mobile項目,開發時便於區分,若是你的項目比較少,那能夠把appName寫成一個固定字符串如:pages,每次切換項目只更改projectName就能夠了。咱們將全部項目放在src下,相似目錄以下github
├─mobile
│ ├─demo
│ └─demo2
└─pc
├─demo
└─demo2
複製代碼
paths.js
,用於配置一些全局須要用到的路徑web
'use strict'
const path = require('path')
const fs = require('fs')
const _config = require('./_config')
const rootPath = fs.realpathSync(process.cwd()) // 項目根目錄 fs.realpathSync表示獲取真實路徑
const resolve = relativePath => path.resolve(rootPath, relativePath) // 自定義一個resolve函數,拼接出須要的路徑地址
module.exports = {
rootPath, // 項目根目錄
commonPath: resolve('common'), // 公共目錄
projectPath: resolve(`src/${_config.appName}/${_config.projectName}`), // 子項目根目錄
config: resolve('config'), // 項目配置
static: resolve('static') // 公共靜態資源目錄
}
複製代碼
咱們在src同級新建一個common文件夾,用於存放靜態資源及公共組件vue-cli
-components
├─assets
├─components
└─xhr
複製代碼
assets裏能夠存放公共樣式css,公共字體font,公共圖片img,公共方法js等;components裏存放提取出來的公共組件,xhr我放的是axio的封裝,整個文件夾能夠自定義修改,這裏就不展開了,若是項目比較簡單不須要,在paths.js裏刪去對應的部分便可。
再來看咱們修改的entry,咱們在config文件夾中的utils.js 新增了getEntry方法,並在entry處引用。
'use strict'
// 省略...
const paths = require('./paths')
const fs = require('fs')
// 省略...
exports.getEntry = () => {
const entryPath = path.resolve(paths.projectPath, 'entry')
const entryNames = fs
.readdirSync(entryPath)
.filter(n => /\.js$/g.test(n))
.map(n => n.replace(/\.js$/g, ''))
const entryMap = {}
entryNames.forEach(
name =>
(entryMap[name] = [
...['babel-polyfill', path.resolve(entryPath, `${name}.js`)] // 這裏須要安裝一下babel-polyfill
])
)
return entryMap
}
複製代碼
實際上就是對當前項目entry文件中的js文件進行遍歷,若是是單個就是單入口,多個就是多入口。
demo1是一個單入口項目,demo2是一個多入口項目,若是是多入口項目,須要在entry增長對應的js文件,如上圖中的more.html和more.js,上面的getEntry其實找的就是index.js和more.js。 咱們再看一下demo2中entry中的index.js和more.js
// index.js
import Vue from 'vue'
import App from '../App'
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
複製代碼
// more.js
import Vue from 'vue'
import App from '../More'
new Vue({
el: '#more',
components: { App },
template: '<App/>'
})
複製代碼
引入對應的組件就好,再看下config.js
const host = 'http://xxx.com/api' // 測試地址
module.exports = {
dev: {
// proxy代理配置
proxyTable: {
'/api': {
target: host, // 源地址
changeOrigin: true, // 改變源
logLevel: 'debug',
ws: true,
pathRewrite: {
'^/api': '' // 路徑重寫
}
}
},
},
build: {
// build輸出路徑
assetsRoot: '',
publichPath: ''
}
// 是否啓用postcss-pxtorem插件 https://github.com/cuth/postcss-pxtorem
// pxtorem: true
}
複製代碼
這裏就是根據須要自行配置了,若是不須要徹底能夠不要這個文件,重要的仍是entry的入口文件。
入口改好了,咱們再看出口,找到以下內容
// webpack.dev.conf.js
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
複製代碼
// webpack.prod.conf.js
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// 省略
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
複製代碼
HtmlWebpackPlugin的做用是生成一個 HTML5 文件,CopyWebpackPlugin的做用是將單個文件或整個目錄複製到構建目錄。咱們在utils.js中新建2個方法getHtmlWebpackPlugin和getCopyWebpackPlugin,對這兩個方法進行替換,讓他們支持多入口。改動後以下
// webpack.dev.conf.js
plugins: [
new webpack.DefinePlugin({
'process.env': require('./dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
// 改動
...utils.getHtmlWebpackPlugin(baseWebpackConfig),
// copy custom static assets
// 改動
...utils.getCopyWebpackPlugin()
]
複製代碼
// webpack.prod.conf.js
// 改動
...utils.getHtmlWebpackPlugin(baseWebpackConfig),
// 省略
// 改動
...utils.getCopyWebpackPlugin()
複製代碼
// utils.js
exports.getHtmlWebpackPlugin = baseWebpackConfig => {
const HtmlWebpackPluginList = []
const entryNames = Object.keys(baseWebpackConfig.entry)
entryNames.forEach(name => {
HtmlWebpackPluginList.push(
new HtmlWebpackPlugin(
Object.assign({
filename: config.build.filename && process.env.NODE_ENV == 'production' ? config.build.filename : `${name}.html`,
template: config.build.template && process.env.NODE_ENV == 'production' ? path.resolve(
paths.projectPath, config.build.template) : path.resolve(
paths.projectPath,
`${name}.html`
),
inject: true,
excludeChunks: entryNames.filter(n => n !== name)
},
process.env.NODE_ENV === 'production' ? {
minify: {
removeComments: true,
collapseWhitespace: true
// removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
} : {}
)
)
)
})
return HtmlWebpackPluginList
}
exports.getCopyWebpackPlugin = () => {
const projectStaticPath = path.resolve(paths.projectPath, 'static')
const assetsSubDirectory =
process.env.NODE_ENV === 'production' ?
config.build.assetsSubDirectory :
config.dev.assetsSubDirectory
const rootConfig = {
from: paths.static,
to: assetsSubDirectory,
ignore: ['.*']
}
const projectConfig = {
from: projectStaticPath,
to: assetsSubDirectory,
ignore: ['.*']
}
return [
new CopyWebpackPlugin(
fs.existsSync(projectStaticPath) ? [rootConfig, projectConfig] : [rootConfig]
)
]
}
複製代碼
咱們找到config裏index.js,對其作一些修改,讓咱們能夠在項目裏的config.js中配置代理,打包目錄,讓模板更靈活。
// config/index.js 改造前
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
// 省略
}
複製代碼
//config/index.js 改造後
const paths = require('./paths')
const resolve = relativePath => path.resolve(paths.projectPath, relativePath)
const _config = require(resolve('config.js')) // 子項目webpack配置
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: _config.dev.proxyTable,
// Various Dev Server settings
host: '0.0.0.0', // can be overwritten by process.env.HOST
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: _config.build.assetsRoot || path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: _config.build.publichPath || './',
// 省略
}
複製代碼
到這裏,咱們的多入口配置就基本完成了,注意修改過的配置文件裏一些引用須要加上,檢查下路徑是否正確。
既然咱們的目的就是打造多入口模板,那麼以demo2爲例,運行npm run dev 在若是服務是http://localhost:8080,多頁面入口在瀏覽器訪問時url就是http://localhost:8080/more.html。注意要帶.html哦。 運行npm run build 咱們會發現dist文件夾裏有2個html,說明多入口打包成功
到此咱們的項目模板就配置完成了。之後多人開發、多入口活動均可以在這個項目下進行開發了,此腳手架是用的vue-cli 2,最新的是vue腳手架是cli3,安裝cli3會覆蓋cli2,若是繼續使用cli2的init 須要npm install -g @vue/cli-init
而後就能夠用vue init webpack my-project
了。因爲我這裏的webpack的版本是4.8.3,可能一些配置文件和舊版本略有變化,改造時還需仔細觀察。
此篇不涉及webpack優化,只提供一種配置思路。若是感受文章寫的不夠清楚,或者想直接使用這個模板,個人git上有完整的腳手架 傳送門,若是遇到問題或者好的建議,歡迎提出。