webpack+模板引擎生成多個靜態HTML

需求:

解決方案:

前面四個問題,在別的文章解釋,其他的問題,咱們就在本文討論

html 文件自動引入靜態資源,轉換路徑

這個參考 將模板轉換成 html 文件,html-webpack-plugin 在生成 html 文件時會自動引入資源文件,不過多入口時需要指定引用資源

生成多個頁面

簡單一點,配置多個入口,然後多整幾個 new html-webpack-plugin。但是程序員的本質,是閃電。所以,copy 是不可能的,這輩子都不可能 copy 的,只能寫寫配置文件,然後批量生成這樣子。所以我們可以這樣做,先寫一個配置文件,放置所有的頁面的相關信息,然後寫一個入口生成函數,批量生成入口。具體的做法看代碼:

新建入口文件entrys.js

const path = require('path')

function resolve (dir) {
    return path.join(__dirname, '..', dir)
}

// 這裏的配置信息,建議根據 html-webpack-plugin 的配置項信息編寫,這樣後續的工作會方便一些
let entrys = {
    globalParameters: {},
    list: [
        {
            entry: 'index',	// 入口名稱
            entryPath: resolve('src/script/index.js'),	// 入口文件路徑
            title: '默認頁面',
            template: resolve('src/view/index.html'),	// 模板文件路徑
        },
        {
            entry: 'home',
            entryPath: resolve('src/script/home.js'),
            title: '首頁',
            template: resolve('src/view/home.html'),
        },
    ]
}

module.exports = entrys

然後編寫生成配置的函數,需要生成兩個東西,一個是 webpack 的入口對象,一個是 html-webpack-plugin 對象

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

function resolve (dir) {
    return path.join(__dirname, '..', dir)
}
const isProd = process.env.NODE_ENV === "production";

const defaults = {
    title: '',
    filename: '',
    template: '',
    chunks: '',
    templateParameters: {}
}
console.log(isProd);
// 構建入口
exports.buildEntry = function (entrys) {
    let entry = {};

    entrys.list.forEach(item => {
        if(!item.entry) return;

        entry[item.entry] = item.entryPath;
    })
    
    return entry;
}

// 構建生成 HTML 模板的入口
exports.buildTemplateEntry = function (entrys) {
    let arr = [],
        parameters = entrys.globalParameters;
        
    entrys.list.forEach(item => {
        let opt = Object.assign({}, defaults);

        opt.title = item.title;
        opt.filename = `view/${ item.filename || item.entry }.html`;
        opt.template = item.template;

        opt.templateParameters = item.templateParameters ? 
                Object.assign({}, parameters, item.templateParameters) :
                Object.assign({}, parameters);

        opt.chunks = item.entry ? [item.entry] : [];

        arr.push(new HtmlWebpackPlugin(opt));
    })

    return arr;
}

然後修改 webpack 的配置文件:

const entryHelp = require('./entryHelp')
const entrys = require('../config/entry')

{
	// ....

	entry: entryHelp.buildEntry(entrys),

	// 模板構建
	plugins: [
        ...entryHelp.buildTemplateEntry(entrys)
    ]
    
	// ....
}

到這裏,生成多頁面的配置就完成了。

熱更新

熱更新,顧名思義,修改文件後頁面立馬更新呈現修改後的內容。包括以下內容變更時的熱更新:

  1. js 代碼修改
  2. 靜態資源修改(樣式,圖片)
  3. 模板修改
  4. webpack 或其他配置文件本身被修改

1 和 2 的變動,都可以直接使用 webpack 的熱更新配置 devServer 處理就行,這裏也還是上一下代碼,還有什麼疑問的話建議看官方文檔 webpack熱更新

配置文件的修改:

	devServer: {
	    hot: true
    },
	plugins: [
	
        // 模塊熱替換
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
    ]

還需要在入口文件的末尾加上以下代碼:

if (module.hot) {
    module.hot.accept()
}

然後以 webpack-dev-server 命令啓動服務,就可以實現熱更新了,

webpack-dev-server --config build/webpack.dev.conf.js

html 文件的變動,webpack 沒有默認的監聽處理,需要自己手動配置,做法是在構建完畢的回調裏判斷html是否有更新,有更新則往客戶端推送更新,具體的配置信息如下:

	devServer: {
		// html 文件修改時刷新整個頁面
	    before(app, server, compiler) {
	        const watchFiles = ['.html'];
	
	        compiler.hooks.done.tap('done', () => {
	            const changedFiles = Object.keys(compiler.watchFileSystem.watcher.mtimes);
	
	            if (
	                this.hot
	                && changedFiles.some(filePath => watchFiles.includes(path.parse(filePath).ext))
	            ) {
	                server.sockWrite(server.sockets, 'content-changed');
	            }
	        });
	    },
	}

webpack 配置的變更與其他配置文件變更實際上是無法熱更新的,只能重啓整個服務,雖然重啓就那麼兩個操作

ctrl + c
npm run start

但是程序員皆是閃電,這點操作我也不願意,能不能我保存配置就自動重啓呢?答案是可以的!不過服務啓動方式就得變一變了,不能再直接配置命令,然後直接啓動,得使用 webpack api 調用的方式啓動。首先我們得監聽配置文件的變動,這裏需要藉助一下第三方插件 nodemon 我使用的版本 ^2.0.3。如果文件有變動,則重新執行 指定的 js 文件,nodemon 就是幹這事兒的。

需要先寫一個啓動服務的配置 dev-server.js,以 api 調用的方式啓動 webpack 熱更新服務

const path = require('path')
const webpack = require('webpack')
const webpackDevServer = require('webpack-dev-server');

const baseConfig = require('../config/idnex')	// webpack 的配置文件,具體格式可以參考 vue-cli2 的模板的 conf/index.js 配置文件
const config = require('./webpack.dev.conf')
const compiler = webpack(config);

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

function resolve (dir) {
    return path.join(__dirname, '..', dir)
}

const devConfig = {
    contentBase: resolve('dist'),
    clientLogLevel: 'warning',
    hot: true,
    host: HOST || baseConfig.dev.host,
    port: PORT || baseConfig.dev.port,
    proxy: baseConfig.dev.proxyTable,

    // html 文件修改時刷新整個頁面
    before(app, server, compiler) {
        const watchFiles = ['.html'];

        compiler.hooks.done.tap('done', () => {
            const changedFiles = Object.keys(compiler.watchFileSystem.watcher.mtimes);

            if (
                this.hot
                && changedFiles.some(filePath => watchFiles.includes(path.parse(filePath).ext))
            ) {
                server.sockWrite(server.sockets, 'content-changed');
            }
        });
    },
}

webpackDevServer.addDevServerEntrypoints(config, devConfig);

const server = new webpackDevServer(compiler, devConfig);

server.listen(devConfig.port, 'localhost', () => {
    console.log(`dev server listening on port ${ devConfig.port }`);
});

然後編寫一個 nodemon 的配置文件,指定監聽目錄以及其他的一些配置,配置文件是 json 格式,但是這裏爲了展示,寫成 js 格式
nodemon.json

{
    "ignore": [],	// 希望忽略的目錄
    "watch": ["./build", "./config"]	// 監聽目錄
}

然後在 package.json 加一條腳本命令

"serve": "nodemon build/dev-server.js"

開發的時候,npm run serve 啓動即可,如果修改了 build 或者 config 目錄下的文件,則會重新執行對應的腳本,也就是重啓 webpack 服務

開發模式接口代理

很多時候,接口服務器與 web 項目配置不在一個地方,這種時候就要配置接口代理,接口代理在 webpack 的 devServer.proxy 中配置,下面展示一下簡單的代碼,更多配置可以看官方文檔的 接口代理

devServer: {
   	proxy: {
   		"/api": {
   			target: "https://other-server.example.com",	// 這裏的接口地址一定要帶上請求協議,不能只寫域名
   		}
   	}
}

到這裏,整個 webpack 生成多頁面的開發環境搭建就完成了,項目的 demo 在 GitHub 上, dev 分支,有需要的可以拉下來看看,頁面地址:https://github.com/just-a-developer/webpack-template-html/tree/dev

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章