webpack多頁應用架構(gòu)系列(五):聽說webpack連less/css也能打包烟具?

本文首發(fā)于Array_Huang的技術博客——實用至上袄膏,非經(jīng)作者同意勒魔,請勿轉(zhuǎn)載杨何。
原文地址:https://segmentfault.com/a/1190000006897458
如果您對本系列文章感興趣,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang

前言

過去講前端模塊化沥邻、組件化危虱,更多還是停留在js層面,畢竟js作為一種更典型的程序語言唐全,在這方面的想象和操作空間都更大一些埃跷。但近年來,組件化要求得更多了邮利,HTML/CSS/JS這三件套一件可都不能少(甚至包括其它類型的資源弥雹,比如說圖片),而這樣的組件延届,無疑是高內(nèi)聚的剪勿。

文章簡介

本文將介紹如何使用webpack來打包less/css(沒用過sass,但畢竟也是通過loader來加載的方庭,相信與less無異)厕吉,首先是介紹相關的webpack plugin&loader,然后將介紹如何加載不同應用層次的less/css械念。

用到什么loader了头朱?

《webpack多頁應用架構(gòu)系列(二):webpack配置常用部分有哪些?》里我就說過龄减,webpack的核心只能打包js文件项钮,而js以外的資源都是靠loader進行轉(zhuǎn)換或做出相應的處理的。下面我就來介紹打包less/css所需要的loader。

less-loader

針對less文件烁巫,我們首先需要使用less-loader來加載署隘。less-loader會調(diào)用所依賴的less模塊對less文件進行編譯(包括@import語法)。至于說less-loader所接受的參數(shù)亚隙,實質(zhì)上大部分是傳遞給less模塊使用的參數(shù)磁餐,由于我本人應用less的程度不深,因此沒有傳任何參數(shù)恃鞋、直接就使用了。如果你之前對less模塊就已經(jīng)有了一套配置的話亦歉,請參考less-loader的文檔進行配置恤浪。

另外,less-loader并不會針對url()語法做特別的轉(zhuǎn)換肴楷,因此水由,如果你想把url()語句里涉及到的文件(比如圖片、字體文件等)也一并用webpack打包的話赛蔫,就必須利用管道交給css-loader做進一步的處理砂客。

css-loader

針對css文件,我們需要使用css-loader來加載.css-loader的功能比較強大呵恢,一些新穎的特性比如Local Scope或是CSS Modules都是支持的鞠值。

我目前只用到了css-loader的壓縮功能(Minification),對于這個功能渗钉,有一點是需要注意的彤恶,那就是如果你的代碼里也和我一樣,有許多為了瀏覽器兼容性的廢棄CSS代碼的話鳄橘,請務必關閉autoprefixer已避免你的廢棄CSS代碼被css-loader刪除了声离,形如css?minimize&-autoprefixer

上面提到css-loader會對url()語句做處理瘫怜,這里稍微再說兩句术徊。在less/css里的這url()語句,在css-loader看來鲸湃,就跟require()語句是一樣的赠涮,只要在webpack配置文件里定義好加載各類型資源的loader,那這url()語句實際上什么資源都能處理暗挑。一般我在url()語句都會以相對路徑的方式(相對于此語句所在的less/css文件)來指定文件路徑世囊;請不要使用以/開頭(即相對于網(wǎng)站根目錄,因為對于文件系統(tǒng)來說窿祥,這明顯是令人混淆的)的路徑株憾,盡管css-loader也可以通過設置root參數(shù)來適配。

postcss-loader

習慣用postcss的童鞋們有福啦,webpack可以通過postcss-loader來兼容postcss嗤瞎。由于postcss只算是一個加分項墙歪,因此這里也不作過多介紹,只介紹一下如何把postcss撘進webpack贝奇,不明白的童鞋麻煩先把postcss搞懂了再看虹菲。

放上我的腳手架項目的代碼:

var precss       = require('precss');
var autoprefixer = require('autoprefixer');

module.exports = {
    module: {
        loaders: [
            {
                test:   /\.css$/,
                exclude: /node_modules|bootstrap/,
                loader: 'css?minimize&-autoprefixer!postcss',
            }
        ]
    },
    postcss: function () {
        return [precss, autoprefixer({
            remove: false,
            browsers: ['ie >= 8', '> 1% in CN'],
        })];
    }
}

從loader的配置'css?minimize&-autoprefixer!postcss'上看,實際上就是先讓postcss-loader處理完了再傳遞給css-loader掉瞳。而postcss項則是postcss-loader所接受的參數(shù)毕源,實際上就是返回一個包含你所需要的postcss's plugins的數(shù)組啦,這些plugin有各自的初始化參數(shù)陕习,不過這些都是postcss的內(nèi)容了霎褐,這里就不做介紹了。

用到什么Plugin了该镣?

加載less/css這一塊主要用到的是extract-text-webpack-plugin(下文簡稱為ExtractTextPlugin吧)冻璃,而且由于我用的是webpack 1,因此用的也是相對應webpack 1的版本(1的文檔在這里不要搞錯了哈)损合。

ExtractTextPlugin的作用是把各個chunk加載的css代碼(可能是由less-loader轉(zhuǎn)換過來的)合并成一個css文件并在頁面加載的時候以<link>的形式進行加載省艳。

相對于使用style-loader直接把css代碼段跟js打包在一起并在頁面加載時以inline的形式插入DOM,我還是更喜歡ExtractTextPlugin生成并加載CSS文件的形式嫁审;倒不是看不慣inline的css跋炕,只是用文件形式來加載的話會快很多,尤其后面介紹用webpack來生成HTML的時候律适,這<link>會直接生成在<head>里枣购,那么在CSS的加載上就跟傳統(tǒng)的前端頁面沒有差別了,體驗非常棒擦耀。

ExtractTextPlugin的初始化參數(shù)不多棉圈,唯一的必填項是filename參數(shù),也就是如何來命名生成的CSS文件眷蜓。跟webpack配置里的output.filename參數(shù)類似分瘾,這ExtractTextPlugin的filename參數(shù)也允許使用變量,包括[id]吁系、[name]和[contenthash]德召;理論上來說如果只有一個chunk,那么不用這些變量汽纤,寫死一個文件名也是可以的上岗,但由于我們要做的是多頁應用,必然存在多個chunk(至少每個entry都對應一個chunk啦)蕴坪。這里我是這么設置的:

new ExtractTextPlugin('[name]/styles.css'), [name]對應的是chunk的name肴掷,我在webpack配置中是這樣

[name]對應的是chunk的name敬锐,我在webpack配置中把各個entry的name都按index/indexindex/login這樣的形式來設置了呆瞻,那么最后css的路徑就會像這樣:build/index/index/styles.css台夺,也就是跟chunk的js文件放一塊了(js文件的路徑形如build/index/index/entry.js)。

除了要把這初始化后的ExtractTextPlugin放到webpack配置中的plugins參數(shù)里痴脾,我們還要在loader配置里做相應的修改:

module.exports = {
    module: {
        loaders: [
            {
                test:   /\.css$/,
                exclude: /node_modules|bootstrap/,
                loader: ExtractTextPlugin.extract('css?minimize&-autoprefixer!postcss'),
            }
        ]
    },
}

如此一來颤介,ExtractTextPlugin就算是配置好了。

如何加載不同應用層次的less/css

在我的設計中赞赖,有三種應用層次的less/css代碼段:

  • 基礎的滚朵、公用的代碼段,包括CSS框架前域、在CSS框架上進行定制的CSS theme辕近,基本上每個頁面都會應用到這些CSS代碼段。
  • 組件的代碼段话侄,這里的組件指的是你自己寫的組件亏推,而且組件本身含有js学赛,并負責加載css以及其它邏輯年堆。
  • 每個頁面獨有的CSS代碼段,很可能只是對某些細節(jié)進行微調(diào)盏浇。

首先來回顧一下我設計的文件目錄結(jié)構(gòu):

├─src # 當前項目的源碼
    ├─pages # 各個頁面獨有的部分变丧,如入口文件、只有該頁面使用到的css绢掰、模板文件等
    │  ├─alert # 業(yè)務模塊
    │  │  └─index # 具體頁面
    │  ├─index # 業(yè)務模塊
    │  │  ├─index # 具體頁面
    │  │  └─login # 具體頁面
    │  │      └─templates # 如果一個頁面的HTML比較復雜痒蓬,可以分成多塊再拼在一起
    │  └─user # 業(yè)務模塊
    │      ├─edit-password # 具體頁面
    │      └─modify-info # 具體頁面
    └─public-resource # 各個頁面使用到的公共資源
        ├─components # 組件,可以是純HTML滴劲,也可以包含js/css/image等攻晒,看自己需要
        │  ├─footer # 頁尾
        │  ├─header # 頁頭
        │  ├─side-menu # 側(cè)邊欄
        │  └─top-nav # 頂部菜單
        ├─config # 各種配置文件
        ├─iconfont # iconfont的字體文件
        ├─imgs # 公用的圖片資源
        ├─layout # UI布局,組織各個組件拼起來班挖,因應需要可以有不同的布局套路
        │  ├─layout # 具體的布局套路
        │  └─layout-without-nav # 具體的布局套路
        ├─less # less文件鲁捏,用sass的也可以,又或者是純css
        │  ├─base-dir
        │  ├─components-dir # 如果組件本身不需要js的萧芙,那么要加載組件的css比較困難给梅,我建議可以直接用less來加載
        │  └─base.less # 組織所有的less文件
        ├─libs # 與業(yè)務邏輯無關的庫都可以放到這里
        └─logic # 業(yè)務邏輯

基礎代碼段

基礎的CSS代碼(實際上我的項目中用的都是less)我統(tǒng)一都放到src/public-resource/less目錄里。我使用一個抽象的文件base.less將所有的less文件組織起來(利用@import)双揪,這樣的話我用js加載起來就方便多了动羽。

在我的腳手架項目(Array-Huang/webpack-seed)里,CSS框架我用的是bootstrap渔期,并且使用了bootstrap-loader進行加載运吓,因此就沒有把bootstrap的CSS文件放到src/public-resource/less/base-dir目錄里,這個目錄里放的都是我定制的theme了。

src/public-resource/less/components-dir目錄放的是某些第三方組件所用到的css羽德,又或是不含js的組件所用到的css几莽。其實這部分CSS是否應該歸在下一類,我也考慮良久宅静,只是由于歸到下一類的話加載起來不方便章蚣,不方便原因如下:

  • 某些第三方庫是要你自己加載CSS的,如果你打算寫適配器來封裝這些第三方庫姨夹,那自然可以直接在適配器來加載CSS纤垂,這就屬于下一類了;然而磷账,有一些使用起來很簡單的庫峭沦,你還寫適配器那就有點畫蛇添足了。
  • 某些自己寫的組件可能僅包含HTML和CSS逃糟,那么誰來加載CSS吼鱼?

所以干脆還是交由base.less一并加載了算了。

我設計了一個common.page.js绰咽,并在每一個頁面的入口文件里都首先加載這common.page.js菇肃,那么,只要我在這common.page.js里加載base.less取募,所有的頁面都能享受到這份基礎CSS代碼段琐谤。

組件代碼段

組件的代碼我都放在了src/public-resource/components,每一個組件統(tǒng)一放在一個獨立的目錄玩敏,并由該組件的js負責加載其CSS斗忌。

頁面代碼段

頁面獨有的CSS我自然是放在該頁面自己的目錄里,利用該頁面的入口文件進行加載旺聚。

最終生成的CSS代碼都在哪织阳?

由于我使用了ExtractTextPlugin,因此這些CSS代碼最終都會生成到所屬chunk的目錄里成為一個CSS文件砰粹。

  • 基礎代碼段肯定是保存在CommonsChunkPlugin所生成的公共代碼chunk所在的目錄里了唧躲,在我的腳手架項目(Array-Huang/webpack-seed)里就是build/commons了(我的公共代碼chunk的name是'commons')。
  • 組件代碼段看情況伸眶,該組件用的頁面多的話(大于CommonsChunkPlugin的minChunks參數(shù))就會被歸到跟基礎代碼段一起咯惊窖;反之,則哪個頁面用到它厘贼,就放到哪個頁面chunk的目錄里咯界酒。
  • 頁面代碼段就不用想了,肯定是在那個頁面chunk的目錄里了嘴秸,畢竟才用了1次毁欣。

示例代碼

諸位看本系列文章庇谆,搭配我在Github上的腳手架項目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed)

附系列文章目錄(同步更新)

本文首發(fā)于Array_Huang的技術博客——實用至上帕翻,非經(jīng)作者同意,請勿轉(zhuǎn)載萝风。
原文地址:https://segmentfault.com/a/1190000006897458
如果您對本系列文章感興趣嘀掸,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市闹丐,隨后出現(xiàn)的幾起案子横殴,更是在濱河造成了極大的恐慌被因,老刑警劉巖卿拴,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異梨与,居然都是意外死亡堕花,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門粥鞋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缘挽,“玉大人,你說我怎么就攤上這事呻粹『韭” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵等浊,是天一觀的道長腮郊。 經(jīng)常有香客問我,道長筹燕,這世上最難降的妖魔是什么轧飞? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任衅鹿,我火速辦了婚禮,結(jié)果婚禮上过咬,老公的妹妹穿的比我還像新娘大渤。我一直安慰自己,他們只是感情好掸绞,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布泵三。 她就那樣靜靜地躺著,像睡著了一般衔掸。 火紅的嫁衣襯著肌膚如雪切黔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天具篇,我揣著相機與錄音纬霞,去河邊找鬼。 笑死驱显,一個胖子當著我的面吹牛诗芜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播埃疫,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼伏恐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了栓霜?” 一聲冷哼從身側(cè)響起翠桦,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胳蛮,沒想到半個月后销凑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡仅炊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年斗幼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抚垄。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜕窿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呆馁,到底是詐尸還是另有隱情桐经,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布浙滤,位于F島的核電站阴挣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瓷叫。R本人自食惡果不足惜屯吊,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一送巡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盒卸,春花似錦骗爆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虹蓄,卻和暖如春犀呼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背薇组。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工外臂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人律胀。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓宋光,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炭菌。 傳聞我的和親對象是個殘疾皇子罪佳,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容