本文首发于 Array_Huang的技术博客——实用至上
,非经做者赞成,请勿转载。
原文地址:https://segmentfault.com/a/1190000006897458
若是您对本系列文章感兴趣,欢迎关注订阅这里:https://segmentfault.com/blog/array_huang
过去讲前端模块化、组件化,更多仍是停留在js层面,毕竟js做为一种更典型的程序语言,在这方面的想象和操做空间都更大一些。但近年来,组件化要求得更多了,HTML/CSS/JS这三件套一件可都不能少(甚至包括其它类型的资源,好比说图片),而这样的组件,无疑是高内聚
的。javascript
本文将介绍如何使用webpack来打包less/css(没用过sass,但毕竟也是经过loader来加载的,相信与less无异),首先是介绍相关的webpack plugin&loader,而后将介绍如何加载不一样应用层次的less/css。css
在《webpack多页应用架构系列(二):webpack配置经常使用部分有哪些?》里我就说过,webpack的核心只能打包js文件,而js之外的资源都是靠loader进行转换或作出相应的处理的。下面我就来介绍打包less/css所须要的loader。前端
针对less文件,咱们首先须要使用less-loader来加载。less-loader会调用所依赖的less
模块对less文件进行编译(包括@import
语法)。至于说less-loader所接受的参数,实质上大部分是传递给less
模块使用的参数,因为我本人应用less的程度不深,所以没有传任何参数、直接就使用了。若是你以前对less
模块就已经有了一套配置的话,请参考less-loader的文档进行配置。java
另外,less-loader并不会针对url()
语法作特别的转换,所以,若是你想把url()
语句里涉及到的文件(好比图片、字体文件等)也一并用webpack打包的话,就必须利用管道交给css-loader作进一步的处理。node
针对css文件,咱们须要使用css-loader来加载.css-loader的功能比较强大,一些新颖的特性好比Local Scope
或是CSS Modules
都是支持的。webpack
我目前只用到了css-loader的压缩功能(Minification),对于这个功能,有一点是须要注意的,那就是若是你的代码里也和我同样,有许多为了浏览器兼容性的废弃CSS代码的话,请务必关闭autoprefixer
已避免你的废弃CSS代码被css-loader删除了,形如css?minimize&-autoprefixer
。git
上面提到css-loader会对url()
语句作处理,这里稍微再说两句。在less/css里的这url()
语句,在css-loader看来,就跟require()
语句是同样的,只要在webpack配置文件里定义好加载各种型资源的loader,那这url()
语句实际上什么资源都能处理。通常我在url()
语句都会以相对路径的方式(相对于此语句所在的less/css文件)来指定文件路径;请不要使用以/
开头(即相对于网站根目录,由于对于文件系统来讲,这明显是使人混淆的)的路径,尽管css-loader也能够经过设置root
参数来适配。github
习惯用postcss的童鞋们有福啦,webpack能够经过postcss-loader来兼容postcss。因为postcss只算是一个加分项,所以这里也不做过多介绍,只介绍一下如何把postcss撘进webpack,不明白的童鞋麻烦先把postcss搞懂了再看。web
放上个人脚手架项目的代码:bootstrap
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所接受的参数,实际上就是返回一个包含你所须要的postcss's plugins的数组啦,这些plugin有各自的初始化参数,不过这些都是postcss的内容了,这里就不作介绍了。
加载less/css这一块主要用到的是extract-text-webpack-plugin
(下文简称为ExtractTextPlugin
吧),并且因为我用的是webpack 1
,所以用的也是相对应webpack 1
的版本(1的文档在这里不要搞错了哈)。
ExtractTextPlugin的做用是把各个chunk加载的css代码(多是由less-loader转换过来的)合并成一个css文件并在页面加载的时候以<link>
的形式进行加载。
相对于使用style-loader直接把css代码段跟js打包在一块儿并在页面加载时以inline的形式插入DOM,我仍是更喜欢ExtractTextPlugin生成并加载CSS文件的形式;倒不是看不惯inline的css,只是用文件形式来加载的话会快不少,尤为后面介绍用webpack来生成HTML的时候,这<link>
会直接生成在<head>
里,那么在CSS的加载上就跟传统的前端页面没有差异了,体验很是棒。
ExtractTextPlugin的初始化参数很少,惟一的必填项是filename
参数,也就是如何来命名生成的CSS文件。跟webpack配置里的output.filename参数相似,这ExtractTextPlugin的filename参数也容许使用变量,包括[id]、[name]和[contenthash];理论上来讲若是只有一个chunk,那么不用这些变量,写死一个文件名也是能够的,但因为咱们要作的是多页应用,必然存在多个chunk(至少每一个entry都对应一个chunk啦)。这里我是这么设置的:
new ExtractTextPlugin('[name]/styles.css'), // [name]对应的是chunk的name,我在webpack配置中是这样
[name]
对应的是chunk的name,我在webpack配置中把各个entry的name都按index/index
、index/login
这样的形式来设置了,那么最后css的路径就会像这样:build/index/index/styles.css
,也就是跟chunk的js文件放一块了(js文件的路径形如build/index/index/entry.js
)。
除了要把这初始化后的ExtractTextPlugin放到webpack配置中的plugins
参数里,咱们还要在loader配置里作相应的修改:
module.exports = { module: { loaders: [ { test: /\.css$/, exclude: /node_modules|bootstrap/, loader: ExtractTextPlugin.extract('css?minimize&-autoprefixer!postcss'), } ] }, }
如此一来,ExtractTextPlugin就算是配置好了。
在个人设计中,有三种应用层次的less/css代码段:
组件
指的是你本身写的组件,并且组件自己含有js,并负责加载css以及其它逻辑。首先来回顾一下我设计的文件目录结构:
├─src # 当前项目的源码 ├─pages # 各个页面独有的部分,如入口文件、只有该页面使用到的css、模板文件等 │ ├─alert # 业务模块 │ │ └─index # 具体页面 │ ├─index # 业务模块 │ │ ├─index # 具体页面 │ │ └─login # 具体页面 │ │ └─templates # 若是一个页面的HTML比较复杂,能够分红多块再拼在一块儿 │ └─user # 业务模块 │ ├─edit-password # 具体页面 │ └─modify-info # 具体页面 └─public-resource # 各个页面使用到的公共资源 ├─components # 组件,能够是纯HTML,也能够包含js/css/image等,看本身须要 │ ├─footer # 页尾 │ ├─header # 页头 │ ├─side-menu # 侧边栏 │ └─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 # 与业务逻辑无关的库均可以放到这里 └─logic # 业务逻辑
基础的CSS代码(实际上个人项目中用的都是less)我统一都放到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是否应该归在下一类,我也考虑良久,只是因为归到下一类的话加载起来不方便,不方便缘由以下:
因此干脆仍是交由base.less
一并加载了算了。
我设计了一个common.page.js
,并在每个页面的入口文件里都首先加载这common.page.js
,那么,只要我在这common.page.js
里加载base.less
,全部的页面都能享受到这份基础CSS代码段。
组件的代码我都放在了src/public-resource/components
,每个组件统一放在一个独立的目录,并由该组件的js负责加载其CSS。
页面独有的CSS我天然是放在该页面本身的目录里,利用该页面的入口文件进行加载。
因为我使用了ExtractTextPlugin,所以这些CSS代码最终都会生成到所属chunk的目录里成为一个CSS文件。
build/commons
了(个人公共代码chunk的name是'commons')。诸位看本系列文章,搭配我在Github上的脚手架项目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed
)。
https://segmentfault.com/a/1190000006843916
https://segmentfault.com/a/1190000006863968
https://segmentfault.com/a/1190000006871991
https://segmentfault.com/a/1190000006887523
https://segmentfault.com/a/1190000006897458
https://segmentfault.com/a/1190000006907701
https://segmentfault.com/a/1190000006952432
https://segmentfault.com/a/1190000006992218
https://segmentfault.com/a/1190000007030775
https://segmentfault.com/a/1190000007043716
https://segmentfault.com/a/1190000007104372
https://segmentfault.com/a/1190000007126268
https://segmentfault.com/a/1190000007159115
本文首发于 Array_Huang的技术博客——实用至上
,非经做者赞成,请勿转载。
原文地址:https://segmentfault.com/a/1190000006897458
若是您对本系列文章感兴趣,欢迎关注订阅这里:https://segmentfault.com/blog/array_huang