原文地址: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,即只是将样式嵌入到分离文件中。这个可能仍是须要具体问题具体分析了。