require('myStyle.css')
這時我們便需要引入相應的webpack loader來幫助我們解析這段代碼。
壹般來說需要引入css-loader和style-loader,其中css-loader用於解析,而style-loader則將解析後的樣式嵌入js代碼。
// webpack配置如下
{
module: {
loaders: [
{ test: /\.$/, loader: "style-loader!css-loader" }
]
}
}
可以發現,webpack的loader的配置是從右往左的,從上面代碼看的話,就是先使用css-loader之後使用style-loader。
同理,如果妳使用less來寫樣式的話,則需要先用less-loader來編譯樣式文件為css文件,再繼續使用css-loader與style-loader。
{
module: {
loaders: [
{ test: /\.$/, loader: "style-loader!css-loader!less-loader" }
]
}
}
我們知道,webpack配置loader時是可以不寫loader的後綴明-loader,因此css-loader可以寫為css。
將樣式抽取出來為獨立的文件
將require引入的樣式嵌入js文件中,有好處也有壞處。好處是減少了請求數,壞處也很明顯,就是當妳的樣式文件很大時,造成編譯的js文件也很大。
我們可以使用插件的方式,將樣式抽取成獨立的文件。使用的插件就是extract-text-webpack-plugin
基本用法如下
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])
該插件實例的唯壹標誌,壹般是不會傳的,其自己會生成。
文件名。可以是[name]、[id]、[contenthash]
[name]:將會和entry中的chunk的名字壹致
[id]:將會和entry中的chunk的id壹致
[contenthash]:根據內容生成hash值
options
allchunk: 是否將所有額外的chunk都壓縮成壹個文件
disable:禁止使用插件
這裏的參數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})
]
postcss
以前我們寫樣式時,有些樣式不同瀏覽器需要加不同的前綴,如-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;
}
postcss後記
這裏再說壹個問題,有些童鞋可能會在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抽取公***代碼
首先要明確壹點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']}),
...
]
}