詳解如何快速配置webpack多入口腳手架
背景
當(dāng)我們基于vue開發(fā)單個(gè)項(xiàng)目時(shí),我們會init一個(gè)vue-cli,但當(dāng)我們想在其他項(xiàng)目里共用這套模板時(shí),就需要重新init一個(gè),或者clone過來,這非常不方便,而且當(dāng)多人開發(fā)時(shí),我們希望所有的開發(fā)代碼都在一個(gè)git目錄下,這時(shí)就有了對webpack進(jìn)行配置的需求,當(dāng)有些頁面需要多入口時(shí),我們又產(chǎn)生了對多入口配置的需求,這里提供一種配置方案,希望能幫助到有需要的人,廢話不多說,我們開始吧!
先初始化一個(gè)項(xiàng)目
我們通過vue init webpack demo 生成的文件目錄是這樣的

修改項(xiàng)目入口
要改多入口,首先改造一下 webpack.base.conf.js 中的 context 和 entry 。
context:基礎(chǔ)目錄,絕對路徑,用于從配置中解析入口起點(diǎn)(entry point)和 loader。
entry:起點(diǎn)或是應(yīng)用程序的起點(diǎn)入口。從這個(gè)起點(diǎn)開始,應(yīng)用程序啟動(dòng)執(zhí)行。
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
};
如果項(xiàng)目只有一個(gè)入口,那么直接在這里改entry就可以了,但一般我們都是多個(gè)項(xiàng)目在放一個(gè)目錄里,所以要提取出來context和entry。
const paths = require('./paths')
const rootPath = paths.rootPath
module.exports = {
context: rootPath
entry: {
app: utils.getEntry(),
},
};
在config里新建 _config.js 和 paths.js
_config.js ,用于設(shè)置當(dāng)前啟動(dòng)項(xiàng)目,并將這個(gè)文件添加到.gitignore中,因?yàn)橐院蠖嗳碎_發(fā)都是在本地修改項(xiàng)目地址。
'use strict'
module.exports = {
appName: 'mobile',
projectName: 'demo'
}
這里設(shè)計(jì)2個(gè)目錄,appName是src下的一級目錄,projectName是appName下的二級目錄,目的在于方便拓展,比如公司的項(xiàng)目分為pc項(xiàng)目和mobile項(xiàng)目,開發(fā)時(shí)便于區(qū)分,如果你的項(xiàng)目比較少,那可以把a(bǔ)ppName寫成一個(gè)固定字符串如:pages,每次切換項(xiàng)目只更改projectName就可以了。我們將所有項(xiàng)目放在src下,類似目錄如下
├─mobile │ ├─demo │ └─demo2 └─pc ├─demo └─demo2
paths.js ,用于配置一些全局需要用到的路徑
'use strict'
const path = require('path')
const fs = require('fs')
const _config = require('./_config')
const rootPath = fs.realpathSync(process.cwd()) // 項(xiàng)目根目錄 fs.realpathSync表示獲取真實(shí)路徑
const resolve = relativePath => path.resolve(rootPath, relativePath) // 自定義一個(gè)resolve函數(shù),拼接出需要的路徑地址
module.exports = {
rootPath, // 項(xiàng)目根目錄
commonPath: resolve('common'), // 公共目錄
projectPath: resolve(`src/${_config.appName}/${_config.projectName}`), // 子項(xiàng)目根目錄
config: resolve('config'), // 項(xiàng)目配置
static: resolve('static') // 公共靜態(tài)資源目錄
}
新建common文件夾
我們在src同級新建一個(gè)common文件夾,用于存放靜態(tài)資源及公共組件
-components ├─assets ├─components └─xhr
assets里可以存放公共樣式css,公共字體font,公共圖片img,公共方法js等;components里存放提取出來的公共組件,xhr我放的是axio的封裝,整個(gè)文件夾可以自定義修改,這里就不展開了,如果項(xiàng)目比較簡單不需要,在paths.js里刪去對應(yīng)的部分即可。
再來看我們修改的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`)]
])
)
return entryMap
}
實(shí)際上就是對當(dāng)前項(xiàng)目entry文件中的js文件進(jìn)行遍歷,如果是單個(gè)就是單入口,多個(gè)就是多入口。
創(chuàng)建2個(gè)項(xiàng)目

- assets 靜態(tài)資源
- config.js 代理配置、打包地址等配置
- entry 入口文件夾
demo1是一個(gè)單入口項(xiàng)目,demo2是一個(gè)多入口項(xiàng)目,如果是多入口項(xiàng)目,需要在entry增加對應(yīng)的js文件,如上圖中的more.html和more.js,上面的getEntry其實(shí)找的就是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/>'
})
引入對應(yīng)的組件就好,再看下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: path.resolve(process.cwd(), '')
}
// 是否啟用postcss-pxtorem插件 https://github.com/cuth/postcss-pxtorem
// pxtorem: true
}
}
這里就是根據(jù)需要自行配置了,如果不需要完全可以不要這個(gè)文件,重要的還是entry的入口文件。
打包出口配置
入口改好了,我們再看出口,找到如下內(nèi)容
// 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的作用是生成一個(gè) HTML5 文件,CopyWebpackPlugin的作用是將單個(gè)文件或整個(gè)目錄復(fù)制到構(gòu)建目錄。我們在utils.js中新建2個(gè)方法getHtmlWebpackPlugin和getCopyWebpackPlugin,對這兩個(gè)方法進(jìn)行替換,讓他們支持多入口。改動(dòng)后如下
// 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
// 改動(dòng)
...utils.getHtmlWebpackPlugin(baseWebpackConfig),
// copy custom static assets
// 改動(dòng)
...utils.getCopyWebpackPlugin()
]
// webpack.prod.conf.js // 改動(dòng) ...utils.getHtmlWebpackPlugin(baseWebpackConfig), // 省略 // 改動(dòng) ...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]
)
]
}
修改index.js
我們找到config里index.js,對其做一些修改,讓我們可以在項(xiàng)目里的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')) // 子項(xiàng)目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為例,運(yùn)行npm run dev 在如果服務(wù)是http://localhost:8080,多頁面入口在瀏覽器訪問時(shí)url就是http://localhost:8080/more.html。注意要帶.html哦。
運(yùn)行npm run build 我們會發(fā)現(xiàn)dist文件夾里有2個(gè)html,說明多入口打包成功

到此我們的項(xiàng)目模板就配置完成了。以后多人開發(fā)、多入口活動(dòng)都可以在這個(gè)項(xiàng)目下進(jìn)行開發(fā)了,此篇不涉及webpack優(yōu)化,只提供一種配置思路。如果感覺文章寫的不夠清楚,或者想直接使用這個(gè)模板,我的git上有完整的腳手架
傳送門 ,如果遇到問題或者好的建議,歡迎提出。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索功能
這篇文章主要為大家詳細(xì)介紹了基于bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
微信小程序swiper左右擴(kuò)展各顯示一半代碼實(shí)例
這篇文章主要介紹了微信小程序swiper左右擴(kuò)展各顯示一半代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
JS實(shí)現(xiàn)動(dòng)態(tài)添加DOM節(jié)點(diǎn)和事件的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)動(dòng)態(tài)添加DOM節(jié)點(diǎn)和事件的方法,涉及javascript事件響應(yīng)及針對頁面dom元素節(jié)點(diǎn)與屬性的動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-04-04
three.js中正交與透視投影相機(jī)的實(shí)戰(zhàn)應(yīng)用指南
在three.js中攝像機(jī)的作用就是不斷的拍攝我們創(chuàng)建好的場景,然后通過渲染器渲染到屏幕中,下面這篇文章主要給大家介紹了關(guān)于three.js中正交與透視投影相機(jī)應(yīng)用的相關(guān)資料,需要的朋友可以參考下2022-08-08
Bootstrap作品展示站點(diǎn)實(shí)戰(zhàn)項(xiàng)目2
這篇文章主要為大家分享了Bootstrap作品展示站點(diǎn)實(shí)戰(zhàn)項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
前端使用crypto-js庫aes加解密詳細(xì)代碼示例
在前端開發(fā)中數(shù)據(jù)的加密和解密是為了保障用戶隱私和數(shù)據(jù)的安全性而常見的任務(wù),這篇文章主要給大家介紹了關(guān)于前端使用crypto-js庫aes加解密的相關(guān)資料,需要的朋友可以參考下2024-03-03

