原文地址:https://github.com/zhengweikeng/blog/issues/9css
咱們能夠在js中引入樣式文件html
require('myStyle.css')
這時咱們便須要引入相應的webpack loader來幫助咱們解析這段代碼。webpack
通常來講須要引入css-loader和style-loader,其中css-loader用於解析,而style-loader則將解析後的樣式嵌入js代碼。git
// webpack配置以下
{
module: { loaders: [ { test: /\.$/, loader: "style-loader!css-loader" } ] } }
能夠發現,webpack的loader的配置是從右往左的,從上面代碼看的話,就是先使用css-loader以後使用style-loader。github
同理,若是你使用less來寫樣式的話,則須要先用less-loader來編譯樣式文件爲css文件,再繼續使用css-loader與style-loader。web
{ module: { loaders: [ { test: /\.$/, loader: "style-loader!css-loader!less-loader" } ] } }
咱們知道,webpack配置loader時是能夠不寫loader的後綴明-loader,所以css-loader能夠寫爲css。npm
將require引入的樣式嵌入js文件中,有好處也有壞處。好處是減小了請求數,壞處也很明顯,就是當你的樣式文件很大時,形成編譯的js文件也很大。瀏覽器
咱們可使用插件的方式,將樣式抽取成獨立的文件。使用的插件就是extract-text-webpack-pluginbabel
基本用法以下less
var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") } ] }, plugins: [ new ExtractTextPlugin("styles.css") ] }
根據插件在github上的解釋,ExtractTextPlugin.extract能夠有三個參數。
第一個參數是可選參數,傳入一個loader,當css樣式沒有被抽取的時候可使用該loader。
第二個參數則是用於編譯解析的css文件loader,很明顯這個是必須傳入的,就像上述例子的css-loader。
第三個參數是一些額外的備選項,貌似目前只有傳入publicPath,用於當前loader的路徑。
那何時須要傳入第一個參數呢,那就得明白何時樣式不會被抽取出來。
瞭解過code splittiog的同窗便會知道,咱們有些代碼在加載頁面的時候不會被使用時,使用code splitting,能夠實現將這部分不會使用的代碼分離出去,獨立成一個單獨的文件,實現按需加載。
那麼若是在這些分離出去的代碼中若是有使用require引入樣式文件,那麼使用ExtractTextPlugin這部分樣式代碼是不會被抽取出來的。
這部分不會抽取出來的代碼,可使用loader作一些處理,這就是ExtractTextPlugin.extract第一個參數的做用。
根據上面的案例,ExtractTextPlugin須要配合plugin使用。
new ExtractTextPlugin([id: string], filename: string, [options])
這裏的參數filename裏如何理解呢?上述案例指定了一個固定的名字,所以便會生成一個styles.css文件。
那麼像[name]、[id]這些如何理解。這個在你有多個entry的時候,便須要使用這種方式來命名。
var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: { "script": "./src/entry.js", "bundle": "./src/entry2.js", }, ... module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") } ] }, plugins: [ new ExtractTextPlugin("[name].css") ] }
這時候便會生成兩個css文件,一個是script.css,另外一個即是bundle.css。那些[id]、[contenthash]也是一個道理。
只要明白,在你有多個entry是,必定要使用這種方式來命名css文件。
最後還有那個allchunks又是什麼呢?很簡單,還記得前面提到的code splitting麼?將該參數配置爲true,那麼全部分離文件的樣式也會所有壓縮到一個文件上。
plugins: [ new ExtractTextPlugin("[name].css", {allChunks: true}) ]
之前咱們寫樣式時,有些樣式不一樣瀏覽器須要加不一樣的前綴,如-webkit-。如今有了構建工具,咱們便不須要再去關注這些前綴了,構建工具會自動幫咱們加上這些前綴。
對於webpack咱們天然想到須要使用loader或者plugin來幫助咱們作這些事情,查了下發現autoprefixer-loader已經廢棄再也不維護了,推薦使用posscss
postcss是用於在js中轉換css樣式的js插件,須要搭配其餘插件一塊兒使用,這點和babel6同樣,自己只是個轉換器,並不提供代碼解析功能。
這裏咱們須要autoprefixer插件來爲咱們的樣式添加前綴。首先下載該模塊。
npm install autoprefixer --save-dev
接着即可以配置webpack了
var autoprefixer = require('autoprefixer') module.exports = { ... module: { loaders: [ ... { { test: /\.css$/, loader: ExtractTextPlugin.extract(["css-loader", "postcss-loader"]) }, } ] }, postcss: [autoprefixer()], ... }
查看一下抽取出來的樣式文件即可以發現已經加上了前綴
a {
display: flex; } /*compiles to:*/ a { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex }
另外autoprefixer還能夠根據目標瀏覽器版本生成不一樣的前綴個數,例如你的應用的使用用戶若是大多數是使用比較新版本的瀏覽器,那麼即可以作以下配置。
postcss: [autoprefixer({ browsers: ['last 2 versions'] })]
這是生成的樣式便會有些不同,仍是上面的例子
a {
display: flex; } /*compiles to:*/ a { display: -webkit-flex; display: -ms-flexbox; display: flex; }
這裏再說一個問題,有些童鞋可能會在css文件中使用@import引入其餘樣式文件,可是使用autoprefixer發現,import進來的樣式沒有處理,以下面所示:
/*myStyle.css:*/
body { background-color: gray; } .flex { display: flex; } /*myStyle2.css:*/ @import "./myStyle.css"; .div { color: red; } /*autoprefixer以後*/ body { background-color: gray; } .flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } body { background-color: gray; } .flex { display: flex; } .div { color: red; }
要解決這個問題,postcss有個解釋,它讓咱們使用postcss-import插件,再配合autoprefixer
postcss: function(webpack) { return [ postcssImport({ addDependencyTo: webpack }), autoprefixer ] },
其實咱們是不推薦使用@import的,心細的童鞋能夠看到最後生成的樣式文件有樣式是重複的。
因此通常咱們應該是在js中使用require來引入樣式文件。能夠參考的說法這裏
壓縮代碼咱們可使用webpack的內置插件UglifyJsPlugin來作,它既能夠壓縮js代碼也能夠壓縮css代碼。
plugins: [
... new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), ... ]
其實並不能說是在壓縮css代碼,本質來講仍是壓縮js代碼,再將這塊代碼輸出到css文件中。
首先要明確一點CommonsChunkPlugin是在有多個entry時使用的,即在有多個入口文件時,這些入口文件可能會有一些共同的代碼,咱們即可以將這些共同的代碼抽取出來成獨立的文件。明白這一點很是重要。(搞了好久才明白的一點,唉~~~~)
若是在多個entry中require了相同的css文件,咱們即可以使用CommonsChunkPlugin來將這些共同的樣式文件抽取出來爲獨立的樣式文件。
module.exports = { entry: { "A": "./src/entry.js", "B": "./src/entry2.js" }, ... plugins: [ new webpack.optimize.CommonsChunkPlugin({name: "commons", filename: "commons.js"}), ... ] }
固然,這裏不止會抽取共同的css,若是有共同的js代碼,也會抽取成爲commons.js。
這裏有個有趣的現象,抽取出來的css文件的命名將會是參數中name的值,而js文件名則會是filename的值。
CommonsChunkPlugin好像只會將全部chunk中都共有的模塊抽取出來,若是存在以下的依賴
// entry1.js
var style1 = require('./style/myStyle.css') var style2 = require('./style/style.css') // entry2.js require("./style/myStyle.css") require("./style/myStyle2.css") // entry3.js require("./style/myStyle2.css")
使用插件後會發現,根本沒有生成commons.css文件。
若是咱們只須要取前兩個chunk的共同代碼,咱們能夠這麼作
module.exports = { entry: { "A": "./src/entry.js", "B": "./src/entry2.js", "C": "./src/entry3.js" }, ... plugins: [ new webpack.optimize.CommonsChunkPlugin({name: "commons", filename: "commons.js", chunks: ['A', 'B']}), ... ] }
根據webpack官網中關於stylesheet的說法,建議是不要將allChunks設爲true,即只是將樣式嵌入到分離文件中。這個可能仍是須要具體問題具體分析了。