使用 webpack 搭建多入口專案
閒來無事,學習一下怎麼用 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檔案中分號一定要帶上