本次目標
多模塊集成的 vue 項目识埋,多項目共用一份配置凡伊,可以互相依賴,也可以獨立打包部署窒舟。
所有操作只需要使用不同操作命令即可系忙,如npm run dev:proj1
或者 npm run dev:proj2
。
使用業(yè)務場景
- 如果多個項目使用
同一樣式
或依賴 相同的 js / 組件
, 可以每個項目都
導入一次惠豺,但后期維護時, 公用引用的部分一旦修改就會就牽一發(fā)而動全身银还,所有引用此文件的都得改動,有些繁瑣洁墙。 - 如果項目有多個子模塊(同時子模塊之間又存在互相依賴關系)蛹疯;對于這樣的場景是可以把項目獨立發(fā)布到
npm倉庫
,但是這樣又涉及到每個模塊都需要獨立編譯好再發(fā)布热监,實際過程有顯得有些繁瑣捺弦。
對于以上場景可以使用一個項目管理多個子模塊也是一個不錯的選擇
多頁面 和 多模塊的區(qū)別
多頁面
:指一個項目有多個入口,打包是會生成多個html
文件孝扛,實際開發(fā)過程中都是混合在一個項目中開發(fā)列吼;
多模塊
:是指不同的業(yè)務模塊可以進行拆分;各自獨立運行苦始、也可以互相引用寞钥,這一點和通過npm
發(fā)布是類似的;
對于一些項目本身不允許發(fā)布的情況下陌选,既可以獨立開發(fā)理郑,又不需要發(fā)布到共有倉庫;
多模塊優(yōu)點
- 高復用性
- 統(tǒng)一管理依賴庫
- 不同模塊使用的依賴各自按需打包
- 模塊之間相互獨立運行、編譯咨油、打包
- 模塊之間可以直接互相引用您炉,不需要 iframe
接下來我們看下具體配置步驟~~見證奇跡的時刻
第一步: 把src
目錄下的文件換成多模塊的形式
項目模塊結構安裝上面的改動完畢之后,控制臺會報一些路徑錯誤之類的:
這是因為
webpack.base.conf.js
里面的main.js
的路徑發(fā)生改變導致的臼勉,之前項目是單模塊只要一個
main.js
邻吭,現(xiàn)在換成多模塊之后每個模塊都有自己獨立的
main.js
餐弱,故此要修改配置宴霸。
第二步: 增加config/multi.conf.js
多模塊配置文件
const path = require('path')
const pack = require('../package.json')
const argvs = process.argv.slice(2)
class MultiModule {
constructor(multiName, opts) {
let datetime = Date.now(),
name = multiName.split('_')[0];
Object.assign(this, {
name,
multiName,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
port: 8080,
host: '0.0.0.0',
proxyTable: null,
entry: {
app: ['babel-polyfill', `./src/${name}/main.js`]
},
alias: resolve(`src/${name}`),
index: path.resolve(__dirname, `../dist/${name}/index.html`),
favicon: path.resolve(__dirname, `../src/${name}/assets/favicon.ico`),
assetsRoot: path.resolve(__dirname, `../dist/${name}/`),
pubdate: `${name}_v${pack.version}_${datetime}`,
publics: [name].concat(opts.statics || []),
deployConfig: null
}, opts)
}
}
// 多模塊獨立配置 ==> 所有模塊的入口選擇
var importModules = [
new MultiModule('proj1', {
port: 8081,
statics: ['static1'],
assetsPublicPath: '/',
baseUrl: '/api/',
proxyTable: {
'/api/': getProxyConfig({ '^/ent': '/' }, 'http://XX.XX.XX.XX')
}
}),
new MultiModule('proj2', {
port: 8082,
statics: ['static2'],
assetsPublicPath: '/',
baseUrl: '/api/',
proxyTable: {
'/api/': getProxyConfig({ '^/ent': '/' }, 'http://XX.XX.XX.XX')
}
}),
new MultiModule('proj3', {
port: 8083,
statics: ['static1'],
assetsPublicPath: '/',
baseUrl: '/api/',
proxyTable: {
'/api/': getProxyConfig({ '^/ent': '/' }, 'http://XX.XX.XX.XX')
}
})
]
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
function getParams(key) {
let item = argvs.find(item => item.split('=')[0] === key)
return item ? item.split('=') : []
}
function getModuleAlias() {
let alias = {}
importModules.forEach(({ name }) => {
alias[`@${name}`] = resolve(`src/${name}`)
})
return alias
}
function getModuleProcess(name) {
let mItem = importModules.find(item => item.multiName === name)
return mItem || importModules[0]
}
function proxyHandle(proxyReq, req, res, options) {
let origin = `${options.target.protocol}//${options.target.hostname}`
proxyReq.setHeader('origin', origin)
proxyReq.setHeader('referer', origin)
}
function onProxyReq(proxyReq, req, res, options) {
proxyHandle(proxyReq, req, res, options)
}
function onProxyReqWs(proxyReq, req, socket, options, head) {
proxyHandle(proxyReq, req, socket, options)
}
// 生成代理類
function getProxyConfig(pathRewrite, target, options) {
return Object.assign({
target,
secure: false,
changeOrigin: true,
ws: false,
// cookieDomainRewrite: { '*': '' },
// cookiePathRewrite: { '*': '/' },
onProxyReq,
onProxyReqWs,
pathRewrite: pathRewrite
}, options)
}
var lifecycleEvents = String(process.env.npm_lifecycle_event).split(':')
var moduleName = getParams('name')[1] || lifecycleEvents[1]
const multiConfig = {
modules: importModules,
moduleAlias: getModuleAlias(),
process: getModuleProcess(moduleName),
}
module.exports = multiConfig;
第三步:修改build/webpack.base.conf.js
文件
- 引入新配置
const multiConfig = require('../config/multi.conf')
- 修改入口配置
entry: multiConfig.process.entry
// 之前為 app: ['babel-polyfill',./src/${name}/main.js
] - 修改資源路徑
publicPath: process.env.ASSETS_PUBLICPATH
- 修改
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@comm': resolve(`src/comm`),
'@': multiConfig.process.alias,
...multiConfig.moduleAlias
}
第四步:修改 build/webpack.dev.conf.js 與 build/webpack.prod.conf.js 文件
- 引入新配置
const multiConfig = require('../config/multi.conf')
- 可根據(jù) 項目本身需要 進行相應修改
plugins
new webpack.DefinePlugin({
'process.env.PROJ_NAME': '\"' + process.env.PROJ_NAME + '\"',
'process.env.BASE_URL': '\"' + process.env.BASE_URL + '\"',
'process.env.ASSETS_PUBLICPATH': '\"' + process.env.ASSETS_PUBLICPATH + '\"',
'process.env.ASSETS_SUBDIRECTORY': '\"' + process.env.ASSETS_SUBDIRECTORY + '\"',
'process.env.FILE_BASE_URL': '\"' + process.env.FILE_BASE_URL + '\"',
'process.env.SOCKET_URL': '\"' + process.env.SOCKET_URL + '\"'
})
build/webpack.dev.conf.js 文件 修改如下:
- 引入文件
const chalk = require('chalk')
const pack = require('../package.json')
const os = require('os')
- 新增此方法 放在 頂部
function getIPAdress () {
var interfaces = os.networkInterfaces()
for (var devName in interfaces) {
var iface = interfaces[devName]
for (var i = 0; i < iface.length; i++) {
var alias = iface[i]
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
return alias.address
}
}
}
}
let host = ['localhost', '127.0.0.1', '0.0.0.0'].includes(devWebpackConfig.devServer.host) ? 'localhost' : devWebpackConfig.devServer.host
- 修改
compilationSuccessInfo
//舊配置
// compilationSuccessInfo: {
// messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
// },
//新配置
compilationSuccessInfo: {
messages: [
chalk`{bold.rgb(255,255,0) [${pack.name} => ${multiConfig.process.name}]} App running at:\n - Local: {bold.cyan http://${host}:${port}${config.dev.assetsPublicPath}}\n - Network: {bold.cyan http://${getIPAdress()}:${port}${config.dev.assetsPublicPath}}`
]
}
build/webpack.prod.conf.js 文件 修改如下:
- 引入 fs 文件
const fs = require('fs')
- 在頭部新增此方法
function isDirectory (path) {
try {
let stat = fs.statSync(path)
return stat.isDirectory()
} catch (e) {
return false
}
}
- 修改
CopyWebpackPlugin
// copy custom static assets 舊配置
// new CopyWebpackPlugin([
// {
// from: path.resolve(__dirname, '../static'),
// to: config.build.assetsSubDirectory,
// ignore: ['.*']
// }
// ])
// copy custom static assets 新配置
new CopyWebpackPlugin(multiConfig.process.publics.filter(name => isDirectory(path.resolve(__dirname, `../static/${name}`))).map(name => {
return {
from: path.resolve(__dirname, `../static/${name}`),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
})),
第五步:修改 build/index.js 文件
- 引入新配置
const multiConfig = require('../config/multi.conf')
- 放入全局對象
process.env.PROJ_NAME = multiConfig.process.name;
process.env.BASE_URL = multiConfig.process.baseUrl;
process.env.FILE_BASE_URL = multiConfig.process.fileBaseUrl;
process.env.SOCKET_URL = multiConfig.process.socketUrl;
process.env.ASSETS_SUBDIRECTORY= multiConfig.process.assetsSubDirectory;
process.env.ASSETS_PUBLICPATH = multiConfig.process.assetsPublicPath;
process.env.ASSETS_PUBLICS = multiConfig.process.publics;
(3). 修改dev
配置
assetsSubDirectory: multiConfig.process.assetsSubDirectory
assetsPublicPath: multiConfig.process.assetsPublicPath
proxyTable: multiConfig.process.proxyTable
host: multiConfig.process.host
port: multiConfig.process.port
(4).修改build
配置
assetsSubDirectory: multiConfig.process.assetsSubDirectory
assetsPublicPath: multiConfig.process.assetsPublicPath
第六步: 配置package.json
文件
"scripts": {
"dev:proj1": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"dev:proj2": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"dev:proj3": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"build": "npm install && npm run build:proj1 && npm run build:proj2 && npm run build:proj3 ",
"build:proj1": "node build/build.js name=proj1",
"build:proj2": "node build/build.js name=proj2",
"build:proj3": "node build/build.js name=proj3"
}
第七步:啟動 / 打包 項目
npm run dev:proj1
npm run dev:proj2
npm run dev:proj3
npm run build :proj1
npm run build :proj2
npm run build :proj3
根據(jù)不同的命令啟動 或 打包 對應 的 模塊項目已經(jīng)完成啦 ~~~