最近寫復旦二手平臺的時候開始嘗試用一直推崇了好久的組件化。通過一番抉擇以後選擇了 webpack + angular 的組合。因此在這裏分享一下具體的實踐流程。javascript
Webpack是目前比較流行的前端打包工具,它同時支持AMD、CMD兩種模塊寫法,也原生支持npm或者bower安裝的模塊。它還能給css、scss、less、coffeescript、es六、圖片、html以及諸如jade、ejs的模板打包。css
因此有什麼卵用呢?html
簡單地說就是,前端
一、原來你須要在<script>
中引入angular或者其餘的npm模塊(有些npm模塊甚至沒有提供能夠直接在瀏覽器端引用的js文件),如今只須要:java
npm install angular
而後在app.js中:node
angular = require('angular'); var app = angular.module('myApp',[]);
而後執行webpack
webpack app.js bundle.js
webpack會自動分析依賴,而後編譯,這樣bundle.js
就是你想要的東西了。git
二、組件化的時候你要在頁面中引入一大堆東西,好比這樣:es6
<!--index.html--> <script type="text/javascript" src="header.js"> <script type="text/javascript" src="tab.js"> <script type="text/javascript" src="waterfoo.js"> <link rel="stylesheet" type="text/css" href="header.css"> <link rel="stylesheet" type="text/css" href="tab.css"> <link rel="stylesheet" type="text/css" href="waterfoo.css">
固然你可能不會用如此傻的方式引入組件,但若是用了webpack以後只須要這樣:github
//index-bundle.js require('header.js'); require('header.scss'); require('tab.js'); require('tab.scss'); require('waterfoo.js'); require('waterfoo.scss');
而後在index.html中引入打包好的js便可(沒錯連scss都給你打包好了/w\ 它甚至還能把圖片打包成base64,而後替換全部url):
<!--index.html--> <script type="text/javascript" src="bundle.js">
上面只是最基礎的用法,因此有些人可能要吐槽這不是browserify也能幹麼/w\ 能夠看看這篇文章[《用webpack來取代browserify》
](http://segmentfault.com/a/1190000002490637),以及webpack還有不少酷炫的功能這裏就再也不贅述。
回到正題吧,復旦二手平臺這個項目更像是多頁面的網站而不是單頁面的web應用,因此我決定嘗試用node去寫一個渲染層(我的感受Koajs目前還不太成熟,因此選用了Express4.0),這樣後臺寫JAVA的同窗就只須要給我提供數據API就好了,把數據庫接口化。
渲染引擎用的是jade,而angular的角色更像是一個頁面的「控制器」,控制由jade生成的頁面,而不是去自行加載html自行渲染(說白了就是放棄了用angular渲染頁面)。
Angular自帶了Module以及Directive機制,但Angular1.x版本下,我以爲這些機制不太適合作這種多頁面網站的組件化,並且也違背了選用jade渲染的初衷。
Angular本身有本身獨特的依賴注入以及模塊聲明方式,看起來彷佛和Webpack是水火不容的,但事實上他們徹底能夠融合。只須要多幾行代碼:
主文件app.js大概長這樣:
var angular = require('angular'); var starkAPP = angular.module('starkAPP', [ ]); module.exports = starkAPP;
注意到咱們在這裏把starkAPP做爲模塊的接口暴露出去,而後咱們就能夠這樣寫controller:
//someController.js var starkAPP = require('./app.js'); starkAPP.controller('someController', ['$scope', function($scope) { //... }])
運行一下webpack someController.js bundle.js
即生成了一個可使用的bundle.js。
固然若是你有一堆controller、directive、service,最好用個main.js
所有聲明一下依賴:
//main.js require('./Controller1'); require('./Controller2'); require('./Controller3'); require('./Service'); require('./Directive');
這裏我只放了瀏覽器端的文件結構,整個的項目結構能夠看這裏
|package.json 存放npm相關的配置 |gulpfile.js gulp的配置文件 |webpack.config.js 存放webpack相關的配置 |build 存放構建完畢的資源文件 |node_modules 不解釋了= = |src 源代碼 └── components 組件 ├── angular angular組件,好比各類directive、service ├── base 須要全站引入的組件,好比reset.css └── header 頭部組件 ├── header.jade ├── header.scss └── header.js └── pages 頁面定義文件 └── index 首頁配置文件 ├── index.js └── index.scss └── template 提供給node渲染的jade模板 └── index.jade 首頁模板
看文件結構絕對是雲裏霧裏的,下面詳細說明:
一、首先這是首頁的模板index.jade
html(ng-app="starkAPP") head link(rel='stylesheet',href='/static/css/index.css') script(type='text/javascript',src='/static/js/index.bundle.js') body(ng-view) include ../components/header/header.jade
注意到咱們引入了header的jade,以及兩個文件index.css
和index.bundle.js
二、index.css
是啥?
它是pages/index/
裏面的index.scss
編譯成的:
// pages/index/index.scss @import '../../components/header/header'; @import '../../components/base/base';
注意到咱們在這裏引入了header.scss
三、index.bundle.js
是啥?
它是pages/index/
裏面的index.js
通過webpack打包成的東西
// pages/index/index/js require('../../components/angular/app.js'); require('../../components/header/header.js');
咱們在這裏引入了angular以及header.js
總之,pages下面放的就是各個頁面的組件依賴文件
好比個人首頁index依賴了一個組件header,那麼我須要在index.js
和index.scss
中聲明我依賴了header.js
以及header.scss
其實用webpack打包的話,只須要一個定義文件就能夠同時打包js和scss,但我還不太肯定webpack打包scss這種方法是否成熟。
自動構建工具我選擇了gulp全家桶,簡單地說就是讀取src/pages/[page-name]
下面全部的js、scss文件,把他們編譯到對應的build/[page-name]
下面,而且監聽文件變化以便熱替換。
這是個人gulpfile.js
:
var gulp = require('gulp'); var sass = require('gulp-sass'), autoprefixer = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), uglify = require('gulp-uglify'), clean = require('gulp-clean'), webpack = require('gulp-webpack'); var webpackConfig = require('./webpack.config'); gulp.task('default', ['clean', 'watch', 'sass:watch', 'sass', 'webpack']); gulp.task('sass:watch', function() { gulp.watch('src/pages/*/*.scss', ['sass']); gulp.watch('src/components/*/*.scss', ['sass']); }); gulp.task('sass', function() { gulp.src(['src/pages/**/*.scss']) .pipe(sass.sync().on('error', sass.logError)) .pipe(minifycss()) .pipe(gulp.dest('build/pages')); }); gulp.task('clean', function() { return gulp.src(['build/pages'], { read: false }) .pipe(clean()); }); gulp.task("webpack", function() { return gulp .src('./') .pipe(webpack(webpackConfig)) //.pipe(uglify()) .pipe(gulp.dest('./build/pages')); }); gulp.task('watch', function() { gulp.watch('src/components/*/*.js', ['webpack']); gulp.watch('src/pages/*/*.js', ['webpack']); });
以及簡化後的webpack.config.js
:
module.exports = { entry: { 'index/index': './src/pages/index/index.js' }, output: { filename: '[name].bundle.js' } };
好比如今咱們要寫一個waterfoo(瀑布流)組件
首先咱們在src/components/
下面新建一個文件夾waterfoo
,而後創建
waterfoo.jade
waterfoo.scss
waterfoo.js
分別對應waterfoo組件的模板、樣式、以及行爲,固然waterfoo組件徹底能夠依賴其餘更低層級組件,只須要在相應的文件中聲明依賴便可。
好比如今咱們要把waterfoo(瀑布流)組件加到首頁index中
首先在src/template/index.jade
中引入模板:
include ../components/waterfoo/waterfoo.jade
而後在src/pages/index/
下面的index.js
、index.scss
配置依賴:
//index.js require('../../components/waterfoo/waterfoo');
//index.scss @import '../../components/waterfoo/waterfoo';
固然有,將來的指望是用webpack把js和scss一塊兒打包,而且把template
和pages
文件夾合併(具體配置express渲染路徑的方法我還在探索),大概就是這樣的效果:
src/pages/index/
下面放着首頁的配置文件:
index.jade
index-config.js
index.scss (一些非組件的樣式)
index.jade是模板
html(ng-app="starkAPP") head script(type='text/javascript',src='/static/js/index.bundle.js') body(ng-view) include ../components/header/header.jade
index-config.js聲明依賴的組件
require('../../components/angular/app.js'); require('../../components/header/header.js'); require('../../components/header/header.scss'); require('../../components/waterfoo/waterfoo.js'); require('../../components/waterfoo/waterfoo.scss'); require('./index.scss');
-------
這個項目的源碼在Github · starkwang/FDSHM,FDSHM是Fudan Secondhand Market的縮寫/w\,如今還在慢慢地寫組件中,爭取這學期上線吧……(缺人啊QAQ)