webpack構建下換膚功能的實現思路

帶帶帶帶土發表於2017-11-27

最近專案中要實現一個換膚的功能,大體想了下,記錄一下思路

要實現換膚功能,目標就是打包生成多份皮膚檔案,需要哪個就用哪個

打包生成多份皮膚檔案

因為專案是使用webpack構建的,要想生成多份css檔案,就要在入口中配置多個入口檔案,每個入口檔案會提取出一個css檔案

config.entry={
    app: ['./src/app.js'],
    defaultTheme: ['./src/theme.default.color.js'],
    orangeTheme:['./src/theme.orange.color.js'],
    blueTheme:['./src/theme.blue.color.js'],
}複製程式碼

app.js中

 import "./app.styl" //整個專案的樣式,在各種皮膚下都保持不變的那部分複製程式碼

theme.blue.color.js 藍色皮膚js檔案

import "./theme/blue.styl"複製程式碼

blue.styl 藍色皮膚

@require "./css/skinTheme/var.blue" //樣式變數,整體為藍色風格的顏色值
@require "./css/skinTheme/theme.color" //提取出來的需要換膚的那部分樣式複製程式碼

如程式碼所示,幾個主題js檔案中只是單純的引入了相應的皮膚樣式檔案,這樣,webpack打包後就會生成幾個無用的js檔案和一系列皮膚樣式檔案

到這一步,就得到了需要的皮膚檔案,但是需要注意的是,webpack會將生成的js、css路徑插入到模板html中,所以,我們開啟構建後生成index.html會看到

<html>
    <head>
        <link rel="stylesheet" href="app.xxxx.css">
        <link rel="stylesheet" href="defaultTheme.xxxxx.css">
        <link rel="stylesheet" href="orangeTheme.xxxxx.css">
        <link rel="stylesheet" href="blueTheme.xxxxx.css">
    </head>
    <body>
        <script src="app.xxxx.js"></script>
        <script src="defaultTheme.xxxx.js"></script>
        <script src="orangeTheme.xxxx.js"></script>
        <script src="blueTheme.xxxx.js"></script>
    </body>
</html>複製程式碼

操作index.html

接下來就需要操作打包後的index.html,將多餘的js引用刪掉,將皮膚路徑提取出來,然後將皮膚引用刪掉

也就是要改成這樣的檔案

/build/index.html

<html>
    <head>
        <script>
            window.cssUrls={
                "defaultTheme":"/defaultTheme.4bdb738cdc062e7842ce.css",
                "orangeTheme":"/orangeTheme.4bdb738cdc062e7842ce.css","blueTheme":"/blueTheme.4bdb738cdc062e7842ce.css"
            }
        </script>
        <link rel="stylesheet" href="app.xxxx.css">
    </head>
    <body>
        <script src="app.xxxx.js"></script>
    </body>
</html>複製程式碼

可以寫這樣一個操作檔案的函式

cssExtract.js

const DISTPATH = 'build/index.html'
const cheerio = require('cheerio')
const fs = require('fs')
const chalk = require('chalk')
const prefix = ['defaultTheme', 'orangeTheme', 'blueTheme']
const cssUrls = {}

function extractCss() {
    fs.readFile(DISTPATH, 'utf8', (err, data) => {
        if (err) {
            throw err
        }
        const $ = cheerio.load(data)
        /**
         * 刪除所有主題css,相關連結儲存在window.cssUrls中
         */
        $('link').each((index, item) => {
            const href = $(item).attr('href')
            for (const val of prefix) {
                if (href.indexOf(val) !== -1) {
                    cssUrls[val] = href
                    $(item).remove()
                }
            }
        })
        /**
         * 刪除無用的js
         */
        $('script').each((index, item) => {
            const src = $(item).attr('src')
            for (const val of prefix) {
                if (src && src.indexOf(val) !== -1) {
                    $(item).remove()
                }
            }
        })

        //插入行內js
        $('base').after(`<script>window.cssUrls=${JSON.stringify(cssUrls)}</script>`)

        fs.writeFile(DISTPATH, $.html(), err => {
            if (err) {
                throw err
            }
            console.log(chalk.cyan('extract css url complete.\n'))
        })
    })
}
extractCss()複製程式碼

最後

到這裡,執行 webpack && node cssExtract.js,index.html就變成上面期望的那樣,我們得要了皮膚檔案的一個mapping,並儲存在window.cssUrls中,接下來,通過切換按鈕的方式切換皮膚還是什麼其他的就可以自由發揮了.

需要說明的是,換膚功能的重點是對樣式的重構,將需要換膚的所有樣式提取到一起,通過變數來設定不同的主題

source

相關文章