閑來無事,學習一下怎么用 webpack 自定義多入口項目的打包
項目github地址:https://github.com/xiaoliwang2016/webpack-demo
先來看一下目錄結構

/admin、/home:模塊,可以根據需求分,也可以只需要一個模塊
/htmlConfig:因為是多入口項目,因此需要一個配置文件來記錄多個入口的路徑,以及與模塊之間的層級關系,單入口文件僅需要定義一個入口,webpack會自動追蹤依賴關系,多入口需要定義多個,所以單獨存起來會好一些
/webpack.config.js:webpack配置默認文件,可以根據在開發環境和生成壞境分開
/模塊/html:放置頁面文件
/模塊/html/tpl:放置一些公用的模板
/模塊/js:放置對應的js文件,名稱與html頁面一致
/模塊/css:放置樣式文件
然后來看一下打包后的目錄

js文件統一放置在/dist/js目錄,頁面文件放在各自模塊名稱對應的目錄下
看完最終效果我們來看一下webpack配置項
入口配置文件
首先看一下前面提到的 htmlConfig.js 文件
module.exports = { 'admin' : [ 'index', 'login' ], 'home' : [ 'index' ] }
很簡單,就是記錄了各個模塊下的頁面的名稱,然后在webpack.config.js中拿去到這個配置項,遍歷打包這些頁面
webpack配置文件
webpack會默認讀取根目錄下webpack.config.js文件,通常可以將這個文件拆分成dev和pro,這里用作演示,沒有分開
const path = require('path')
const htmlConfig = require('./htmlConfig.js')
//生成html插件
const htmlWebpackPlugin = require('html-webpack-plugin')
//抽離css插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var htmlWebpackPlugins = []
var entrys = {}
for(var key in htmlConfig){
htmlConfig[key].forEach(item => {
//生成 entry 對象中的 key 例如 { admin-login: './admin/login.html' }
var k = key + '-' + item
htmlWebpackPlugins.push(new htmlWebpackPlugin({
//template設置根據那個模板生成
template: `./src/${key}/html/${item}.html`,
//生成html名稱
filename: `./${key}/${item}.html`,
//chunks 設置需要引入的JS模塊
chunks: [k],
//自動引入js 可選:true(底部)/body/head
inject: true,
}))
entrys[k] = `./src/${key}/js/${item}.js`
})
}
module.exports = {
mode: 'production',
entry: entrys,
output: {
path: path.resolve(__dirname, 'dist'),
// name:對應entry的key ,chunkhash根據文件進行MD5自動計算
filename: 'js/[name]-[chunkhash].js',
//上線時可以使用 publicPath替換根路徑
// publicPath: 'http://cdn.com/'
},
module:{
rules: [
{
test: /\.js$/,
//排除項
exclude: path.resolve(__dirname, 'node_modules'),
//選擇項
include: path.resolve(__dirname, 'src'),
loader: "babel-loader",
//babel需要配合 babel-preset-env 一起使用
query: {
"presets": ["env"]
}
},
{
test: /\.css$/,
//同一個文件需要多個loader的情況下可以使用數組,執行順序根據數組從后往前執行
use: [
//使用MiniCssExtractPlugin.loader代替style-loader抽離css成單獨文件
MiniCssExtractPlugin.loader,
// 'style-loader',
//每個loader可以有自己的參數,options字段就是定義參數
{ loader: 'css-loader', options: {importLoaders: 1}},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
//autoprefixer是postcss-loader的一個插件,需要安裝,用於給css添加前綴
plugins: [
require('autoprefixer')({
cascade: false
})
]
}
}
]
},
{
test: /\.tpl$/,
loader: 'ejs-loader'
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "[id].css"
}),
...htmlWebpackPlugins
]
}
注意:這里需要注意的是使用 loader 打包文件時調用 loader 的順序時根據數組從后往前,因此這里處理css文件的順序時:
postcss-loader --> css-loader --> style-loader
* postcss-loader是一個css后處理器,他提供很多插件可以處理css文件,例如css自動添加前綴,壓縮等等
loader
js
webpack默認只會處理js文件,因此如果有需要處理不同文件時需要指定對應的loader
例如常用轉換js語法的loader:babel-loader
安裝:
npm install babel-loader --save-dev
npm install babel-preset-env --save-dev
然后需要在制定位置添加 presets 配置項
可以是 padkjson.js 或者 .babelrc 文件 或者webpack.config.js中
模板
多入口文件一般一個頁面對應一個js文件,可以在js文件中再次引入其他的模板(頁面),在通過loader解析最后插入到當前頁面

例如這里的/admin/js/index.js對應的模板時/admin/html/index.html,然而還可以在index.js中引入一些其他的模板,例如引入admin/html/tpl/table.tpl,然后渲染插入到index.html中
在處理模板文件時可以根據不同的模板設置不同的loader處理,這里演示的是ejs的模板
<table class="table">
<tr>
<th>brand</th>
<th>name</th>
<th>price</th>
</tr>
<% for(var i = 0; i < data.length; i++) { %>
<tr>
<td><%= data[i].brand %></td>
<td><%= data[i].name %></td>
<td><%= data[i].price %></td>
</tr>
<% } %>
</table>
在webpack.config.js中配置loader
{ test: /\.tpl$/, loader: 'ejs-loader' }
在js文件中可以直接通過import的放置引入該模板文件
import table from '../html/layer/table.tpl'
ejs-loader處理完成后會返回一個函數(html-loader返回為字符串),函數的參數為模板的變量,例如在admin/js/index.js文件中引入模板然后插入到頁面
import '../css/index.css' import table from '../html/layer/table.tpl' document.querySelector('#table').innerHTML = table({ data : [ {brand: 'MI', name: 'MI6', price: 2999}, {brand: 'iphone', name: 'iphoneX', price: 9999} ] })
生成后頁面

樣式
可以在js中直接通過import的方式引入
import '../css/index.css'
也可以在css中引入其他的css文件
@import './common.css';
css文件中分號一定要帶上
