直接上结论:npm+webpack+css-modules
如果现在问我前端应该采用什么样的模块化方案,我会毫不犹豫的推荐他上面的这个组合。前端模块化是一个老生常谈的问题了,前端模块化要解决的问题归纳下来就是以下这些问题:
- 按文件切割模块
- 包依赖管理工具
- 能够整合HTML和CSS
- 按需加载
- 调试发布方便
- 支持 coffeeScript ES6 等扩展
其中第一项是基础,这个没什么可说的。
关于第二项当前有npm和bower,bower是特意为浏览器端设计的,而npm最初只是针对NodeJS。因为有了npm,在NodeJS中的包管理是很方便的,install然后require就好了。但是在浏览器中用bower那么则需要install之后再手动的引入js,所以bower更像是一个CDN,如果当做一个包管理工具来用种是有些那么别扭,尤其是之后要做压缩合并的时候又会带来一堆麻烦事。还有一个原因是bower仅仅管理了一些开源的第三方库,但是你自己的模块管理还需要借助requirejs或者seajs这样的模块加载工具。
那么能不能在浏览器端用npm来管理包依赖呢?答案是可以的。最初我使用的是browserify。最后发现有几个让人不爽的地方:编译慢,配置麻烦,多入口配置困难。似乎browserify最初设计的时候就只是作为一个黑科技,并没有真正去解决前端的痛点。直到后来使用了webpack,整个世界都清爽了,看看下面这个最简单的配置:
1 | module.exports = { |
很清晰有木有!!!而且webpack本身包含了watch模式,因为不像browserify那样去解析整个语法树,所以编译也快了很多。解决了 5. 调试发布方便 的问题。而且从此npm 20多万的包向你敞开啦!
然后你应该注意到配置文件中有module
这项配置,这才是webpack的关键,同事它也解决了模块化问题中的两个问题:3. 能够整合HTML和CSS 6. 支持 coffeeScript ES6 等扩展。webpack不仅仅是将CommonJS规范的JS作为模块来加载,它也可以按照你的设置针对不同的文件采用不同的loader去加载,这意味找你可以去加载一个css文件,可以去加载一个html模板,这些都可以当做一个普通的模块去require。你甚至可以使用ES6的JS模块规范,可以方便的使用jsx开发react应用。一切都是模块!!!
另外关于CSS模块化的问题多说几句,前端的模块化之所以这么困难,自然是逃不开前端所涉及到得HTML,CSS这样的问题。HTML的模块化我们可以用webpack使得把HTML模板转化为一个JS的方法,或者是用jsx来解决。但是CSS呢?CSS是浏览器特有的,CSS是叠加作用再浏览器上的,这也是CSS富有表现力的地方,但是这样也带来了一个CSS模块化的难题。关于这个问题,有一些框架给出了一些解决方案,Polymer的Shady dom或者说webComponent的shadow dom使得CSS可以局部作用,但是却让CSS的复用变得困难。还有之前看过有人用react的CSS in JS,把CSS当做JS来玩。这的确是个思路,但是我写了几次之后就受不了了,用JS的语法来写CSS还不不习惯,不知道习惯之后会不会好。最后发现css-modules,它通解析CSS将其中的class重新构建为一个私有的名字并作为模块的exports暴露出来,这样就能够将一个CSS文件当做一个模块来require,而且也支持继承等形式的复用。
最后这个方案唯一没有解决的问题就是按需加载了,在我参与的项目中并没有JS大到需要多次按需加载的情况,所以这个问题还没有好好考虑过,后续再补上吧。
为什么要花这么大得劲来解决模块化问题,那是因为一个完美的通用的模块化方案最终为促进如下两个方向的改进:
- 统一的模块化规范,使得能够更好的兼容和复用各种开源的第三方包
- 完善的HTML+CSS+JS的模块化方案将会大大推动web前端组件化的进程
试想一下只需要npm install 然后在你的js中require就能够使用一个组件的时候是多么美好。最后附上一个demo。