從搭建vue-腳手架到掌握webpack配置(三.多頁面構建)

前言

上一期中我們通過引入了插件實現(xiàn)了不少功能——樣式抽離做入、公共模塊提取臊泰、代碼壓縮等等蛉加;本期開始講講可能會用到的第三方編譯器的配置和多入口的優(yōu)化。

本期重點:postcss和.babelrc配置缸逃、多入口多頁面代碼提取優(yōu)化

往期鏈接:

從搭建vue-腳手架到掌握webpack配置(一.基礎配置)

從搭建vue-腳手架到掌握webpack配置(二.插件與提取)

小小題外話

本系列文章寫到了第三篇针饥,Jason我發(fā)現(xiàn)了這系列的文章有一個很大的缺陷,文章和前面的文章存在著耦合需频,可能會導致知識點存在線性的關聯(lián)丁眼,對于有基礎的朋友來說,又要從第一期開始閱讀的話昭殉,比較不友好苞七。
所以后面的文章開始Jason會嘗試獨立知識點,盡量回歸知識點的運用上挪丢;在文章的開頭也會說明本期的主要內容蹂风;當然一些插件和loader的進階使用還是要有基礎的,初學者還是建議從頭過一遍乾蓬。

使用postcss

postcss介紹

postcss官方的GitHub上還有中文的介紹硫眨。

PostCSS 是一個允許使用 JS 插件轉換樣式的工具。 這些插件可以檢查(lint)你的 CSS巢块,支持 CSS Variables 和 Mixins, 編譯尚未被瀏覽器廣泛支持的先進的 CSS 語法巧号,內聯(lián)圖片族奢,以及其它很多優(yōu)秀的功能。

簡單來說postcss就是一個css的轉換器丹鸿,有了postcss或許你就不用再用less和sass了越走,通過在postcss上添加插件可以組裝出你需要的語法需求和功能(屬性變量,父子嵌套,版本兼容等)廊敌,在postcss上通常會用的插件有cssnext铜跑、Autoprefixer、postcss-import骡澈。甚至可以在postcss上用less或sass編譯器

用法

這里就用添加Autoprefixer(自動兼容瀏覽器)為例簡單講講postcss的配置方法锅纺,有幾種配置方法

  • 使用配置文件配置 postcss.config.js或.postcssrc.js
  • 使用post-loader的時候通過options配置項配置

建議是使用配置文件進行配置,這樣可以在所有調用到postcss-loader的地方使用同樣的配置

肋殴!值得一提的是其實vue-loader是默認啟用了postcss-loader的囤锉,所以vue-loader的官方文檔里面有直接設置postcss配置項的選項。

所以在有vue-loader的項目里面其實是不用手動安裝npm install -save-dev postcss-loader的护锤,不是vue項目就裝吧官地。

只要在css的loaders里面添加vue-style-loader,就會自動啟用postcss了烙懦,如下

{
    test:/\.less$/,
    use:[
        'vue-style-loader'驱入,
        'css-loader',
        'less-loader'
    ]
    })
},
{
    test:/\.vue$/,
    loader:'vue-loader',
    options:{
        loaders:{
            'css': [
                'vue-style-loader',
                'css-loader',
            ],
            'less': [
                'vue-style-loader'氯析,
                'css-loader',
                'less-loader'
            ]
        },
        //postcss:{}//vue-loader還自帶了這一選項亏较,但是建議用配置文件進行配置
    }
}

引入 Autoprefixer :

  • 需要安裝 autoprefixer插件哦:npm install --save-dev autoprefixer
  • 新建.postcssrc.js文件在跟目錄下,內容如下
module.exports = {
  "plugins": {
    //"postcss-import": {},
    // to edit target browsers: use "browserslist" field in package.json
    "autoprefixer": {}
  }
}

autoprefixer對應的對象{}魄鸦,是該插件的配置項宴杀,有需要可以查閱文檔進行配置;postcss-import插件是@import是可以引本地的文件拾因,如node_modules內的文件旺罢,英文好的去看看該插件介紹。既然vue-cli用了postcss-import我們也這樣用吧绢记,記得安裝npm install --save-dev postcss-import扁达。

autoprefixer會去檢查package.json里的browserslist 配置項作為兼容瀏覽器版本的范圍

//在package.json上添加這一項
"browserslist": [
    "> 5%",
    "last 2 versions",
    "not ie <= 8"
  ]

我們這里就簡單的引入了autoprefixer,沒有做過多的配置蠢熄,如果對postcss感興趣的話可以去看看下面文檔

.babelrc配置

在使用es6語法編寫js的時候跪解,我們都會在webpack上用babel-loader轉換js文件,而.bablrc就是babel編譯js時用的的規(guī)則和插件的配置規(guī)范

像postcss一樣在根目錄下創(chuàng)建名為.babelrc的文件(沒有.js后綴)

{
  "presets": [
    ["env", {
       "modules": false ,
       "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-3"
  ]
}

安裝依賴:

npm install --save-dev babel-presets-env babel-presets-stage-0 

babel-preset-env,本依賴插件是設置編譯環(huán)境的插件签孔,如果直接引入不設置規(guī)則那實際它和引入babel-preset-latest一樣叉讥,會囊括es2015、es2016饥追、es2017图仓。

'modules':false:設置模塊引用規(guī)則,可以設置成"amd" | "umd" | "systemjs" | "commonjs" | false, defaults to "commonjs",設置了false但绕,就是用es6以上默認的規(guī)則救崔。

targets.browsers:設置兼容的瀏覽器范圍

tage-3依賴惶看,ES7不同階段語法提案的轉碼規(guī)則(共有4個階段),選裝一個

babel-presets-stage-0  babel-presets-stage-1
babel-presets-stage-2  babel-presets-stage-3
其他

還可以在里面添加插件實現(xiàn)更多的功能六孵,如添加react的jsx編譯纬黎。像官方給出的示例代碼一樣

{
  "presets":["env"]
  "plugins": ["transform-react-jsx"],
  "ignore": [
    "foo.js",
    "bar/**/*.js"
  ]
}

畢竟這不是babelrc的教程,更高級的使用可以去以下的鏈接去深入學習劫窒。

鏈接

好了本今,整個個系列到目前為止常常會用到的webpack配置、loader烛亦、插件诈泼、編譯器都使用過了。

后面開始就要按照需求煤禽,改進我們的自動化構建配置了铐达。

多頁面、多入口

很多用vue或者react工程環(huán)境都會默認是spa(單頁應用)檬果,但是業(yè)界上也有很多項目傾向于使用vue等框架的組件化功能瓮孙,但是并不引入router模塊,而是使用傳統(tǒng)的路由鏈接选脊;尤其是視頻網(wǎng)站杭抠、購物網(wǎng)站等pc端的網(wǎng)頁是不會做成spa的。所以在一個工程中編輯和生成多個頁面是必須的情況恳啥。

在src目錄下新建home.js文件(內容和main.js一樣就行)偏灿,在webpack的entry項設置多個入口是最方便快捷的方法。

entry:{
    app:'./src/main.js',
    home:'./src/home.js'
},
output:{
    path:path.resolve(__dirname,'./dist'),
    filename:"js/[name].js",
},

entry對應不同的頁面設置不同的入口文件钝的,output.filename要寫成[name]以chunk名命名的形式

看似簡單翁垂,但是我們之前用到公共代碼提取(CommonsChunkPlugin)和css抽離(ExtractTextPlugin)會把整個項目中的代碼打包到一起會影響頁面的加載硝桩。所以我們要改進他的邏輯

css分頁面拆分

這個很簡單沿猜,只要在實例化ExtractTextPlugin插件的同時添加一個allchunks:true參數(shù)就可以了,還有就是把輸出都指向一個css文件,用``[name]```區(qū)分chunk名

const ExtractVueCss = new ExtractTextPlugin({filename:'styles/[name]-style.css',allChunks:true});

按照我的習慣碗脊,先分出一份公共樣式(root.css),其他的按chunk的數(shù)量進行分割啼肩,所以root.css的allchunks:false,其他的true衙伶。

const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const ExtractRootCss = new ExtractTextPlugin({filename:'styles/[name]-root.css',allChunks:false});
const ExtractVueCss = new ExtractTextPlugin({filename:'styles/[name]-style.css',allChunks:true});

module.exports = {
    //other options...
    module:{
        rules:[
        //...
            {
                test:/\.css$/,
                //這里用的ExtractRootCss,輸出到root.css
                use:ExtractRootCss.extract({
                    fallback:'style-loader',
                    use:['css-loader']
                })
            },
            {
                test:/\.less$/,
                //這里用的ExtractRootCss,輸出到root.css
                use:ExtractRootCss.extract({
                    fallback:'style-loader',
                    use:[
                        'css-loader',
                        'less-loader'
                    ]
                })
            },
            {
                test:/\.vue$/,
                loader:'vue-loader',
                options:{
                    loaders:{
                        //這里用的ExtractVueCss
                        'css': ExtractVueCss.extract({
                            use: 'css-loader',
                            fallback: 'vue-style-loader' 
                          }),
                        //這里用的ExtractVueCss
                        'less':
                        ExtractVueCss.extract({
                            use:[
                                'css-loader',
                                'less-loader'
                            ],
                            fallback:'vue-style-loader'
                        })
                    },
                }
            },
        ]
    },
    plugins:[
        //填入插件實例,記得按順序填入
        ExtractRootCss,//root.css
        ExtractVueCss,//vue內的css
        new webpack.HotModuleReplacementPlugin(),
    ]
}

多頁面公共提取

不懂commons-chunk-plugin祈坠,又不想看以前的文章的話看左邊鏈接

之前我們把node_modules內的模塊抽取到了vender.js里面。

//抽取從node_modules引入的模塊矢劲,如vue颁虐,vue-router
new webpack.optimize.CommonsChunkPlugin({
    name: 'vender',
    minChunks:function(module,count){
        var sPath = module.resource;
        // console.log(sPath,count);
        //匹配 node_modules文件目錄
        return sPath &&
            /\.js$/.test(sPath) &&
            sPath.indexOf(
                path.join(__dirname, 'node_modules')
            ) === 0
    }
}),

上上面設置了多個入口chunk,而且output的時候也不是設置成唯一的文件名卧须,這樣webpack打包的時候會自動按照入口chunk的數(shù)量生成相應數(shù)量的代碼包,按目前情況會有app.js和home.js。

但是問題在于每個chunk都會把所有他們用到的模塊單獨打包起來花嘶。比如app和home用到一樣的header.vue模塊笋籽,webpack都會分別打包到app.js和home.js里面。多次復用的模塊最好是可以抽取出來椭员,在首頁加載過js文件之后得到了緩存车海,在詳情頁能馬上得到提升頁面加載速度。

為了解決以上問題隘击,我們再加一個公共代碼提取的實例

new webpack.optimize.CommonsChunkPlugin({
    name:'common'
    minChunks:2
}),

這樣每個頁面(入口chunk)中引入超過兩次的模塊就會打包到common.js文件下面侍芝。

minChunks2代表所有chunk中復用超過2以上的模塊會被提取。寫成2粒度最小埋同,你可以按自己需求修改州叠。

(5.20更新) 實際項目上發(fā)現(xiàn),單一入口的時候凶赁,vendor.js并沒有被抽離咧栗,原因可能是單一入口時common沒被提前導致的(具體原因請大神指教),所以我們要再做一步入口數(shù)量判斷

Object.keys(config.page).length >= 2 
    ? new webpack.optimize.CommonsChunkPlugin({
            name: 'common',
            minChunks:2
        }):()=>{},
抽取webpack的運行時邏輯

參考vue-cli虱肄,我們會認為webpack的加載調度等運行時(runtime)邏輯是不會頻繁修改的致板,所以我們把這部分抽離出來方面以后的頁面都調用它。這樣的話我們在加一個CommonsChunkPlugin實例咏窿,用于抽取這些邏輯斟或。

new webpack.optimize.CommonsChunkPlugin({
    name:'common'
    minChunks:2
}),
new webpack.optimize.CommonsChunkPlugin({
    name: 'vender',
    minChunks:function(module,count){
        var sPath = module.resource;
        return sPath &&
            /\.js$/.test(sPath) &&
            sPath.indexOf(
                path.join(__dirname, 'node_modules')
            ) === 0
    }
}),
//將webpack runtime 和一些復用部分抽取出來
new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    minChunks:Infinity
}),

!注意!這里插件是有引入順序的集嵌,順序不對可能會導致操作被覆蓋萝挤。

minChunksInfinity什么chunk都不抽取出來,只抽取webpack的runtime等邏輯纸淮。

抽取異步公共模塊

在開發(fā)vue或者react的時候可能會用到異步加載模塊的能力(又叫懶加載)平斩,比如import()webpack require.ensure功能異步加載的模塊。vue項目通常是vue-router懶加載組件的時候用到咽块。

雖然做多頁開發(fā)的時候不一定會用到vue-router绘面,但是我們讓構建配置更健壯那就適配到spa的情況,把異步公共模塊的提取也加進去

// 放到上面三個CommonsChunkPlugin的最后

new webpack.optimize.CommonsChunkPlugin({
    // names: ["app", "subPageA"]
    // (選擇 chunks侈沪,或者忽略該項設置以選擇全部 chunks)
    async: 'vendor-async',
    children: true,
    minChunks:2
}),

沒有給name的話就會默認選擇所有入口chunk揭璃。

async:可以使true或者字符串,字符串的話就是生成的公共chunk的名字亭罪。(這個選項一直沒搞懂瘦馍,直到看到了這文章Webpack 大法之 Code Splitting

children:選擇所有被選 chunks 的子 chunks

minChunks:大于等于兩個chunk復用的子模塊會提取到該公共chunk

中文文檔下面的示例有介紹 link

改寫生成的html模板

同樣,懶得看上期文章应役,又不懂HtmlWebpackPlugin的同學點這里

HtmlWebpackPlugin插件在上一期中用到了情组,但是我們只是簡單的設置了模板文件和出口文件燥筷。插件會默認把所有輸出的chunk包和css文件都引入到生成的模板中。我們如下修改一下插件的配置

plugins:[
        new HtmlWebpackPlugin({
            filename:'index.html',
            title:'vue demo',
            // favicon:'./src/images/logo.png',
            template:'./index.html',
            chunks:['app','vender','manifest','common'],
            chunksSortMode: 'dependency'
        }),
        new HtmlWebpackPlugin({
            filename:'home.html',
            title:'vue home',
            template:'./index.html',
            chunks:['home','vender','manifest','common'],
            chunksSortMode: 'dependency'
        }),
    ]

filename:生成的文件名,區(qū)分頁面起對應的名字

template:html模板來源院崇,應為是vue 項目所以用同樣的模板肆氓,你可以按自己的需要來設置

chunks:關鍵的來了,這個就是把本模板關聯(lián)的chunks列舉出來的參數(shù)底瓣,我把各種的入口chunk和提取出來的公共chunk填入了谢揪。

chunksSortMode:chunk的引入順序,'dependency'按依賴關系映入

build一下

運行npm run build,生成的dist文件目錄結構如下

dist目錄

并沒有成產(chǎn)vendor-async.js異步公共模塊是因為項目中還沒有用到異步加載的部分

到目前為止完整的webpack.config.js文件可以到這 下載

ps

Jason建議看別人的webpack配置時遇到不懂的插件多多查 npmjs 或者社區(qū)論壇捐凭,有時間看看去webpack官方介紹的插件或許里面有有你需要的

Jason水平有限拨扶,如果有什么地方的知識點有錯誤請大家多多提點,在評論中告訴我茁肠。

下期預告

上一期的webpack配置完后完全可以應付單頁應用的構建患民,而這一期還適應了多頁面的構建需求,而且還學會了postcss和babelrc的基礎配置方法官套。是不是感覺越來越接近vue-cli創(chuàng)建的項目了呢酒奶?

引入了多頁面的構建思想后,我們發(fā)現(xiàn)如果我們的頁面不斷的增加就要不斷的給webpack.config.js添加插件和邏輯奶赔。所以為了方便和易用性惋嚎,下一期我們來嘗試寫一些封裝邏輯把構建配置封裝起來,用一個文件整合常用的配置項統(tǒng)一對工程進行配置站刑。

下一期可能不會很快能更新另伍,一方面因為手上有事情要忙,另一方面整項目我還沒有封裝測試好(這也正是為什么一直沒有給出github的原因)绞旅,所以請有關注本系列的同學可能要等等了摆尝,有需要的同學也可以關注我的賬號留意更新。

參考

https://github.com/postcss/postcss/blob/HEAD/README.cn.md

PostCSS配置指北.md

PostCSS 是個什么鬼東西因悲?

html-webpack-plugin用法全解

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末堕汞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晃琳,更是在濱河造成了極大的恐慌讯检,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卫旱,死亡現(xiàn)場離奇詭異人灼,居然都是意外死亡,警方通過查閱死者的電腦和手機顾翼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門投放,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人适贸,你說我怎么就攤上這事灸芳±晕Γ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵耗绿,是天一觀的道長苹支。 經(jīng)常有香客問我,道長误阻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任晴埂,我火速辦了婚禮究反,結果婚禮上,老公的妹妹穿的比我還像新娘儒洛。我一直安慰自己精耐,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布琅锻。 她就那樣靜靜地躺著卦停,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恼蓬。 梳的紋絲不亂的頭發(fā)上惊完,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音处硬,去河邊找鬼小槐。 笑死,一個胖子當著我的面吹牛荷辕,可吹牛的內容都是我干的凿跳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼疮方,長吁一口氣:“原來是場噩夢啊……” “哼控嗜!你這毒婦竟也來了?” 一聲冷哼從身側響起骡显,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤疆栏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蟆盐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體承边,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年石挂,在試婚紗的時候發(fā)現(xiàn)自己被綠了博助。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡痹愚,死狀恐怖富岳,靈堂內的尸體忽然破棺而出蛔糯,到底是詐尸還是另有隱情,我是刑警寧澤窖式,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布蚁飒,位于F島的核電站,受9級特大地震影響萝喘,放射性物質發(fā)生泄漏淮逻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一阁簸、第九天 我趴在偏房一處隱蔽的房頂上張望爬早。 院中可真熱鬧,春花似錦启妹、人聲如沸筛严。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桨啃。三九已至,卻和暖如春檬输,著一層夾襖步出監(jiān)牢的瞬間照瘾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工褪猛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留网杆,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓伊滋,卻偏偏與公主長得像碳却,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笑旺,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345