webpack打包后引用cdn的js_呕心沥血编写的webpack多入口零基础配置 【建议收藏】...
最近在做項目的時候遇到了一個場景:一個項目有多個入口,不同的入口,路由、組件、資源等有重疊部分,也有各自不同的部分。由于不同入口下的路由頁面有一些是重復(fù)的,因此我考慮使用 Webpack 多入口配置來解決這個需求。
再一次,在網(wǎng)上找的不少文章都不合我的需求,很多文章都是只簡單介紹了生產(chǎn)環(huán)境下配置,沒有介紹開發(fā)環(huán)境下的配置,有的也沒有將多入口結(jié)合 vue-router、 vuex、 ElementUI 等進行配置,因此在下通過不斷探坑,然后將思路和配置過程記錄下來,留給自己作為筆記,同時也分享給大家,希望可以幫助到有同樣需求的同學(xué)們~
1. 目標(biāo)分析
一個項目中保存了多個 HTML 模版,不同的模版有不同的入口,并且有各自的 router、store 等;
不僅可以打包出不同 HTML,而且開發(fā)的時候也可以順利進行調(diào)試;
不同入口的文件可以引用同一份組件、圖片等資源,也可以引用不同的資源;
代碼倉庫:multi-entry-vue
示意圖如下:
2. 準(zhǔn)備工作
首先我們 vue init webpack multi-entry-vue 使用 vue-cli 創(chuàng)建一個 webpack 模版的項。文件結(jié)構(gòu)如下:
.
├── build
├── config
├── src
│?? ├── assets
│?? │?? └── logo.png
│?? ├── components
│?? │?? └── HelloWorld.vue
│?? ├── router
│?? │?? └── index.js
│?? ├── App.vue
│?? └── main.js
├── static
├── README.md
├── index.html
├── package-lock.json
└── package.json
這里順便介紹在不同系統(tǒng)下生成目錄樹的方法:
mac 系統(tǒng)命令行生成目錄樹的方法?tree-I node_modules--dirsfirst?,這個命令的意思是,不顯示?node_modules?路徑的文件,并且以文件夾在前的排序方式生成目錄樹。如果報沒有找到 tree 命令的錯,安裝 tree 命令行?brew install tree?即可。
windows 系統(tǒng)在目標(biāo)目錄下使用?tree/f1.txt?即可把當(dāng)前目錄樹生成到一個新文件?1.txt?中。
首先我們簡單介紹一下 Webpack 的相關(guān)配置項,這些配置項根據(jù)使用的 Webpack 模版不同,一般存放在 webpack.config.js 或 webpack.base.conf.js 中:
const path = require('path')
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'output-file.js',
publicPath: '/'
},
module: {}, // 文件的解析 loader 配置
plugins: [], // 插件,根據(jù)需要配置各種插件
devServer: {} // 配置 dev 服務(wù)功能
}
這個配置的意思是,進行 Webpack 后,會在命令的執(zhí)行目錄下新建 dist 目錄(如果需要的話),并將打包 src 目錄下的 main.js 和它的依賴,生成 output-file.js 放在 dist 目錄中。
下面稍微解釋一下相關(guān)配置項:
entry:?入口文件配置項,可以為字符串、對象、數(shù)組。以上面的對象形式為例,?app?是入口名稱,如果?output.filename?中有?[name]?的話,就會被替換成?app。
context:?是 webpack 編譯時的基礎(chǔ)目錄,用于解析?entry?選項的基礎(chǔ)目錄(絕對路徑),?entry?入口起點會相對于此目錄查找,相當(dāng)于公共目錄,下面所有的目錄都在這個公共目錄下面。
output:?出口文件的配置項。
output/path:?打包文件輸出的目錄,比如上面的?dist,那么就會將輸出的文件放在當(dāng)前目錄同級目錄的?dist?文件夾下,沒有這個文件夾就新建一個。可以配置為?path.resolve(__dirname,'./dist/${Date.now()}/')?(md 語法不方便改成模板字符串,請自行修改)方便做持續(xù)集成。
output.filename:?輸出的文件名稱,?[name]?的意為根據(jù)入口文件的名稱,打包成相同的名稱,有幾個入口,就可以打包出幾個文件。比如入口的?key?為?app,打包出來就是?app.js,入口是?my-entry,打包出來就是?my-entry.js。
output.publicPath:?靜態(tài)資源的公共路徑,可以記住這個公式:?靜態(tài)資源最終訪問路徑=output.publicPath+資源loader或插件等配置路徑。舉個例子,?publicPath?配置為?/dist/,圖片的?url-loader?配置項為?name:'img/[name].[ext]'?,那么最終打包出來文件中圖片的引用路徑為?output.publicPath+'img/[name].[ext]'='/dist/img/[name].[ext]'。
本文由于是入口和出口相關(guān)的配置,所以內(nèi)容主要圍繞著 entry 、 output 和一個重要的 webpack 插件 html-webpack-plugin,這個插件是跟打包出來的 HTML 文件密切相關(guān),主要有下面幾個作用:
根據(jù)模版生成 HTML 文件;
給生成的 HTML 文件引入外部資源比如?link、?script?等;
改變每次引入的外部文件的 Hash,防止 HTML 引用緩存中的過時資源;
下面我們從頭一步步配置一個多入口項目。
3. 開始配置
3.1 文件結(jié)構(gòu)改動
在 src 目錄下將 main.js 和 App.vue 兩個文件各復(fù)制一下,作為不同入口,文件結(jié)構(gòu)變?yōu)?#xff1a;
.
├── build
│?? ├── build.js
│?? ├── check-versions.js
│?? ├── logo.png
│?? ├── utils.js
│?? ├── vue-loader.conf.js
│?? ├── webpack.base.conf.js
│?? ├── webpack.dev.conf.js # 主要配置目標(biāo)
│?? └── webpack.prod.conf.js # 主要配置目標(biāo)
├── config
│?? ├── dev.env.js
│?? ├── index.js
│?? └── prod.env.js
├── src
│?? ├── assets
│?? │?? └── logo.png
│?? ├── components
│?? │?? └── HelloWorld.vue
│?? ├── router
│?? │?? └── index.js
│?? ├── App.vue
│?? ├── App2.vue # 新增的入口
│?? ├── main.js
│?? └── main2.js # 新增的入口
├── static
├── README.md
├── index.html
└── package.json
3.2 簡單配置
要想從不同入口,打包出不同 HTML,我們可以改變一下 entry 和 output 兩個配置,
// build/webpack.prod.conf.js
module.exports = {
entry: {
entry1: './src/main.js',
entry2: './src/main2.js'
},
output: {
filename: '[name].js',
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({
template: "index.html", // 要打包輸出哪個文件,可以使用相對路徑
filename: "index.html" // 打包輸出后該html文件的名稱
})
]
}
根據(jù)上面一小節(jié)我們知道,webpack 配置里的 output.filename 如果有 [name] 意為根據(jù)入口文件的名稱,打包成對應(yīng)名稱的 JS 文件,那么現(xiàn)在我們是可以根據(jù)兩個入口打包出 entry.js 和 entry2.js。
打包的結(jié)果如下:
當(dāng)前代碼:Github - multi-entry-vue1
如上圖,此時我們 npm run build 打包出一個引用了這兩個文件的 index.html,那么如何打包出不同 HTML 文件,分別應(yīng)用不同入口 JS 文件呢,此時我們需要借助于 HtmlWebpackPlugin 這個插件。
HtmlWebpackPlugin 這個插件, new 一個,就打包一個 HTML 頁面,所以我們在 plugins 配置里 new 兩個,就能打包出兩個頁面來。
3.3 打包出不同的 HTML 頁面
我們把配置文件改成下面這樣:
// build/webpack.prod.conf.js
module.exports = {
entry: {
entry: './src/main.js', // 打包輸出的chunk名為entry
entry2: './src/main2.js' // 打包輸出的chunk名為entry2
},
output: {
filename: '[name].js',
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'entry.html', // 要打包輸出的文件名
template: 'index.html', // 打包輸出后該html文件的名稱
chunks: ['manifest', 'vendor', 'entry'] // 輸出的html文件引入的入口chunk
// 還有一些其他配置比如minify、chunksSortMode和本文無關(guān)就省略,詳見github
}),
new HtmlWebpackPlugin({
filename: 'entry2.html',
template: 'index.html',
chunks: ['manifest', 'vendor', 'entry2']
})
]
}
上面一個配置要注意的是 chunks,如果沒有配置,那么生成的 HTML 會引入所有入口 JS 文件,在上面的例子就是,生成的兩個 HTML 文件都會引入 entry.js 和 entry2.js,所以要使用 chunks 配置來指定生成的 HTML 文件應(yīng)該引入哪個 JS 文件。配置了 chunks 之后,才能達到不同的 HTML 只引入對應(yīng) chunks 的 JS 文件的目的。
大家可以看到除了我們打包生成的 chunk 文件 entry.js 和 entry2.js 之外,還有 manifest 和 vendor 這兩個,這里稍微解釋一下這兩個 chunk:
vendor?是指提取涉及?node_modules?中的公共模塊;
manifest?是對?vendor?模塊做的緩存;
打包完的結(jié)果如下:
文件結(jié)構(gòu):
現(xiàn)在打包出來的樣式正是我們所需要的,此時我們在 dist 目錄下啟動 live-server(如果你沒安裝的話可以先安裝 npm i-g live-server),就可以看到效果出來了:
當(dāng)前代碼:Github - multi-entry-vue2
至此就實現(xiàn)了一個簡單的多入口項目的配置。
4. 配置改進
4.1 文件結(jié)構(gòu)改動
我們在前文進行了多入口的配置,要想新建一個新的入口,就復(fù)制多個文件,再手動改一下對應(yīng)配置。
但是如果不同的 HTML 文件下不同的 vue-router、 vuex 都放到 src 目錄下,多個入口的內(nèi)容平鋪在一起,項目目錄會變得凌亂不清晰,因此在下將多入口相關(guān)的文件放到一個單獨的文件夾中,以后如果有多入口的內(nèi)容,就到這個文件夾中處理。
下面我們進行文件結(jié)構(gòu)的改造:
首先我們在根目錄創(chuàng)建一個?entries?文件夾,把不同入口的?router、?store、?main.js?都放這里,每個入口相關(guān)單獨放在一個文件夾;
在?src?目錄下建立一個?common?文件夾,用來存放多入口共用的組件等;
現(xiàn)在的目錄結(jié)構(gòu):
.
├── build # 沒有改動
├── config # 沒有改動
├── entries # 存放不同入口的文件
│?? ├── entry1
│?? │?? ├── router # entry1 的 router
│?? │?? │?? └── index.js
│?? │?? ├── store # entry1 的 store
│?? │?? │?? └── index.js
│?? │?? ├── App.vue # entry1 的根組件
│?? │?? ├── index.html # entry1 的頁面模版
│?? │?? └── main.js # entry1 的入口
│?? └── entry2
│?? ├── router
│?? │?? └── index.js
│?? ├── store
│?? │?? └── index.js
│?? ├── App.vue
│?? ├── index.html
│?? └── main.js
├── src
│?? ├── assets
│?? │?? └── logo.png
│?? ├── common # 多入口通用組件
│?? │?? └── CommonTemplate.vue
│?? └── components
│?? ├── HelloWorld.vue
│?? ├── test1.vue
│?? └── test2.vue
├── static
├── README.md
├── index.html
├── package-lock.json
└── package.json
4.2 webpack 配置
然后我們在 build/utils 文件中加兩個函數(shù),分別用來生成 webpack 的 entry 配置和 HtmlWebpackPlugin 插件配置,由于要使用 node.js 來讀取文件夾結(jié)構(gòu),因此需要引入 fs、 glob 等模塊:
// build/utils
const fs = require('fs')
const glob = require('glob')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ENTRY_PATH = path.resolve(__dirname, '../entries')
// 多入口配置,這個函數(shù)從 entries 文件夾中讀取入口文件,裝配成webpack.entry配置
exports.entries = function() {
const entryFiles = glob.sync(ENTRY_PATH + '/*/*.js')
const map = {}
entryFiles.forEach(filePath => {
const filename = filePath.replace(/.*\/(\w+)\/\w+(\.html|\.js)$/, (rs, $1) => $1)
map[filename] = filePath
})
return map
}
// 多頁面輸出模版配置 HtmlWebpackPlugin,根據(jù)環(huán)境裝配html模版配置
exports.htmlPlugin = function() {
let entryHtml = glob.sync(ENTRY_PATH + '/*/*.html')
let arr = []
entryHtml.forEach(filePath => {
let filename = filePath.replace(/.*\/(\w+)\/\w+(\.html|\.js)$/, (rs, $1) => $1)
let conf = {
template: filePath,
filename: filename + '.html',
chunks: [filename],
inject: true
}
// production 生產(chǎn)模式下配置
if (process.env.NODE_ENV === 'production') {
conf = merge(conf, {
chunks: ['manifest', 'vendor'],
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
})
}
arr.push(new HtmlWebpackPlugin(conf))
})
return arr
}
稍微解釋一下這兩個函數(shù):
exports.entries 函數(shù)從 entries 文件夾中找到二級目錄下的 JS 文件作為入口文件,并且將二級目錄的文件夾名作為 key,生成這樣一個對象: {"entry1":"/multi-entry-vue/entries/entry1/main.js"},多個入口情況下會有更多鍵值對;
exports.htmlPlugin 函數(shù)和之前函數(shù)的原理類似,不過組裝的是 HtmlWebpackPlugin 插件的配置,生成這樣一個數(shù)組,可以看到和我們手動設(shè)置的配置基本一樣,只不過現(xiàn)在是根據(jù)文件夾結(jié)構(gòu)來生成的:
// production 下
[
{
template: "/multi-entry-vue/entries/entry1/index.html",
chunks: ['manifest', 'vendor', 'entry1'],
filename: "entry1.html",
chunksSortMode: 'dependency'
},
{ ... } // 下一個入口的配置
]
有了這兩個根據(jù) entries 文件夾的結(jié)構(gòu)來自動生成 webpack 配置的函數(shù),下面來改一下 webpack 相關(guān)的幾個配置文件:
// build/webpack.base.conf.js
module.exports = {
entry: utils.entries(), // 使用函數(shù)生成 entry 配置
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
}
}
// build/webpack.dev.conf.js
// const HtmlWebpackPlugin = require('html-webpack-plugin') // 不需要了
const devWebpackConfig = merge(baseWebpackConfig, {
devServer: {
historyApiFallback: {
rewrites: [ // 別忘了把 devserver 的默認路由改一下
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'entry1.html') },
],
}
},
plugins: [
// https://github.com/ampedandwired/html-webpack-plugin
// new HtmlWebpackPlugin({
// filename: 'index.html',
// template: 'index.html',
// inject: true
// }), // 注釋掉原來的 HtmlWebpackPlugin 配置,使用生成的配置
].concat(utils.htmlPlugin())
})
// build/webpack.prod.conf.js
// const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpackConfig = merge(baseWebpackConfig, {
plugins: [
// new HtmlWebpackPlugin({
// ... 注釋掉,不需要了
// }),
].concat(utils.htmlPlugin())
})
現(xiàn)在我們再 npm run build,看看生成的目錄是什么樣的:
此時我們在 dist 目錄下啟動 live-server 看看是什么效果:
當(dāng)前代碼:Github - multi-entry-vue3
網(wǎng)上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學(xué)習(xí)過程中的總結(jié),如果發(fā)現(xiàn)錯誤,歡迎指出~
最后歡迎加我微信(CALASFxiaotan),拉你進技術(shù)群,長期交流學(xué)習(xí)...
歡迎關(guān)注「前端巔峰」,認真學(xué)前端,做個有專業(yè)的技術(shù)人...
總結(jié)
以上是生活随笔為你收集整理的webpack打包后引用cdn的js_呕心沥血编写的webpack多入口零基础配置 【建议收藏】...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c 普通的文本变成注释文本的快捷键_In
- 下一篇: python同时发大量请求_python