詳解如何快速配置webpack多入口腳手架
背景
當(dāng)我們基于vue開(kāi)發(fā)單個(gè)項(xiàng)目時(shí),我們會(huì)init一個(gè)vue-cli,但當(dāng)我們想在其他項(xiàng)目里共用這套模板時(shí),就需要重新init一個(gè),或者clone過(guò)來(lái),這非常不方便,而且當(dāng)多人開(kāi)發(fā)時(shí),我們希望所有的開(kāi)發(fā)代碼都在一個(gè)git目錄下,這時(shí)就有了對(duì)webpack進(jìn)行配置的需求,當(dāng)有些頁(yè)面需要多入口時(shí),我們又產(chǎn)生了對(duì)多入口配置的需求,這里提供一種配置方案,希望能幫助到有需要的人,廢話不多說(shuō),我們開(kāi)始吧!
先初始化一個(gè)項(xiàng)目
我們通過(guò)vue init webpack demo 生成的文件目錄是這樣的
修改項(xiàng)目入口
要改多入口,首先改造一下 webpack.base.conf.js
中的 context
和 entry
。
context:基礎(chǔ)目錄,絕對(duì)路徑,用于從配置中解析入口起點(diǎn)(entry point)和 loader。
entry:起點(diǎn)或是應(yīng)用程序的起點(diǎn)入口。從這個(gè)起點(diǎn)開(kāi)始,應(yīng)用程序啟動(dòng)執(zhí)行。
module.exports = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' }, };
如果項(xiàng)目只有一個(gè)入口,那么直接在這里改entry就可以了,但一般我們都是多個(gè)項(xiàng)目在放一個(gè)目錄里,所以要提取出來(lái)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)橐院蠖嗳碎_(kāi)發(fā)都是在本地修改項(xiàng)目地址。
'use strict' module.exports = { appName: 'mobile', projectName: 'demo' }
這里設(shè)計(jì)2個(gè)目錄,appName是src下的一級(jí)目錄,projectName是appName下的二級(jí)目錄,目的在于方便拓展,比如公司的項(xiàng)目分為pc項(xiàng)目和mobile項(xiàng)目,開(kāi)發(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文件夾
我們?cè)趕rc同級(jí)新建一個(gè)common文件夾,用于存放靜態(tài)資源及公共組件
-components ├─assets ├─components └─xhr
assets里可以存放公共樣式css,公共字體font,公共圖片img,公共方法js等;components里存放提取出來(lái)的公共組件,xhr我放的是axio的封裝,整個(gè)文件夾可以自定義修改,這里就不展開(kāi)了,如果項(xiàng)目比較簡(jiǎn)單不需要,在paths.js里刪去對(duì)應(yīng)的部分即可。
再來(lái)看我們修改的entry,我們?cè)赾onfig文件夾中的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í)際上就是對(duì)當(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增加對(duì)應(yīng)的js文件,如上圖中的more.html和more.js,上面的getEntry其實(shí)找的就是index.js和more.js。
我們?cè)倏匆幌耫emo2中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/>' })
引入對(duì)應(yīng)的組件就好,再看下config.js
const host = 'http://xxx.com/api' // 測(cè)試地址 module.exports = { dev: { // proxy代理配置 proxyTable: { '/api': { target: host, // 源地址 changeOrigin: true, // 改變?cè)? 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的入口文件。
打包出口配置
入口改好了,我們?cè)倏闯隹?,找到如下?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)建目錄。我們?cè)趗tils.js中新建2個(gè)方法getHtmlWebpackPlugin和getCopyWebpackPlugin,對(duì)這兩個(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,對(duì)其做一些修改,讓我們可以在項(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 || './', // 省略 }
到這里,我們的多入口配置就基本完成了,注意修改過(guò)的配置文件里一些引用需要加上,檢查下路徑是否正確。
既然我們的目的就是打造多入口模板,那么以demo2為例,運(yùn)行npm run dev 在如果服務(wù)是http://localhost:8080,多頁(yè)面入口在瀏覽器訪問(wèn)時(shí)url就是http://localhost:8080/more.html。注意要帶.html哦。
運(yùn)行npm run build 我們會(huì)發(fā)現(xiàn)dist文件夾里有2個(gè)html,說(shuō)明多入口打包成功
到此我們的項(xiàng)目模板就配置完成了。以后多人開(kāi)發(fā)、多入口活動(dòng)都可以在這個(gè)項(xiàng)目下進(jìn)行開(kāi)發(fā)了,此篇不涉及webpack優(yōu)化,只提供一種配置思路。如果感覺(jué)文章寫的不夠清楚,或者想直接使用這個(gè)模板,我的git上有完整的腳手架
傳送門 ,如果遇到問(wèn)題或者好的建議,歡迎提出。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
javascript制作的網(wǎng)頁(yè)側(cè)邊彈出框思路及實(shí)現(xiàn)代碼
這篇文章主要介紹了javascript制作的網(wǎng)頁(yè)側(cè)邊彈出框思路及實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-05-05js操作DOM--添加、刪除節(jié)點(diǎn)的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇js操作DOM--添加、刪除節(jié)點(diǎn)的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07TypeScript創(chuàng)建一個(gè)簡(jiǎn)單Web應(yīng)用
這篇文章主要為大家介紹了TypeScript創(chuàng)建一個(gè)簡(jiǎn)單Web應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05前端項(xiàng)目中報(bào)錯(cuò)Uncaught?(in?promise)的解決方法
最近在做項(xiàng)目的時(shí)候控制臺(tái)報(bào)了一個(gè)錯(cuò)Uncaught(in promise) false,這篇文章主要給大家介紹了關(guān)于前端項(xiàng)目中報(bào)錯(cuò)Uncaught?(in?promise)的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04javascript中運(yùn)用閉包和自執(zhí)行函數(shù)解決大量的全局變量問(wèn)題
做為一個(gè)javascript新手,為了程式的簡(jiǎn)便,可能會(huì)在javascript中運(yùn)用了大量的全局變量,雖然一時(shí)看來(lái),問(wèn)題解決了,而且也可能讓編碼變得更加的簡(jiǎn)單。2010-12-12js實(shí)現(xiàn)base64文件的處理以及下載方法
Base64是一種將二進(jìn)制數(shù)據(jù)編碼為ASCII字符的編碼方式,這篇文章主要給大家介紹了關(guān)于js實(shí)現(xiàn)base64文件的處理以及下載的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07微信小程序?qū)崿F(xiàn)滑動(dòng)翻頁(yè)效果(完整代碼)
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)滑動(dòng)翻頁(yè)效果,本文通過(guò)效果圖展示實(shí)例代碼講解的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12如何確保JavaScript的執(zhí)行順序 之實(shí)戰(zhàn)篇
我曾在文章《如何在多個(gè)頁(yè)面使用同一個(gè)HTML片段 - 續(xù)》的最后提到JavaScript順序執(zhí)行的特性。雖然現(xiàn)代瀏覽器可以并行的下載JavaScript(部分瀏覽器),但考慮到JavaScript的依賴關(guān)系,他們的執(zhí)行依然是按照引入順序進(jìn)行的。2011-03-03javascript簡(jiǎn)單實(shí)現(xiàn)圖片預(yù)加載
本文是給大家分享一段簡(jiǎn)單的實(shí)現(xiàn)圖片預(yù)加載技術(shù)的javascript代碼,超級(jí)精簡(jiǎn),卻很實(shí)用,這里推薦給大家2014-12-12