├── components ├── page │ ├── index.jade │ ├── index.js │ ├── index.scss │ └── index.html ├── sprite │ ├── sprite.scss │ ├── icon.png │ ├── autosprite.scss │ └── retina.scss └── project.example.js ├── templates ├── src │ ├── html │ │ ├── include.html │ │ └── master.html │ ├── tpl │ │ ├── common │ │ │ ├── footer.jade │ │ │ └── header.jade │ │ └── index │ │ │ └── list.jade │ ├── libs │ │ └── bootstrap │ │ │ ├── bootstrap.css │ │ │ └── bootstrap.js │ ├── js │ │ ├── common │ │ │ ├── report.js │ │ │ └── global.js │ │ ├── common.js │ │ └── index.js │ ├── test-include.html │ ├── favicon.ico │ ├── css │ │ ├── common │ │ │ ├── _level.scss │ │ │ ├── _ricons.scss │ │ │ └── _reset.scss │ │ └── index.scss │ ├── img │ │ ├── common │ │ │ └── banner.png │ │ ├── sprite │ │ │ ├── icons │ │ │ │ ├── search.png │ │ │ │ └── webqq.png │ │ │ ├── level │ │ │ │ ├── search.png │ │ │ │ └── webqq.png │ │ │ └── icons@2x │ │ │ │ ├── search.png │ │ │ │ └── webqq.png │ │ └── static │ │ │ └── static-img-url.png │ ├── test-extend.html │ └── index.html ├── __gitignore ├── userdef.js ├── __editorconfig ├── README.md ├── __jshintrc ├── project.js ├── package.json ├── config.rb ├── livefile.js └── gulpfile.js ├── .gitignore ├── .npmignore ├── package.json ├── slushfile.js └── README.md /components/page/index.jade: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/page/index.js: -------------------------------------------------------------------------------- 1 | // require(); 2 | -------------------------------------------------------------------------------- /templates/src/html/include.html: -------------------------------------------------------------------------------- 1 | include content -------------------------------------------------------------------------------- /templates/src/tpl/common/footer.jade: -------------------------------------------------------------------------------- 1 | this is a footer -------------------------------------------------------------------------------- /templates/src/libs/bootstrap/bootstrap.css: -------------------------------------------------------------------------------- 1 | body {} 2 | -------------------------------------------------------------------------------- /templates/src/js/common/report.js: -------------------------------------------------------------------------------- 1 | // frontend report kit 2 | -------------------------------------------------------------------------------- /components/page/index.scss: -------------------------------------------------------------------------------- 1 | @charset"UTF-8"; 2 | @import"common/reset"; 3 | -------------------------------------------------------------------------------- /templates/src/libs/bootstrap/bootstrap.js: -------------------------------------------------------------------------------- 1 | console.log('bootstrap.js'); 2 | -------------------------------------------------------------------------------- /templates/src/tpl/common/header.jade: -------------------------------------------------------------------------------- 1 | p #{title} 2 | this is a pre header 3 | 4 | -------------------------------------------------------------------------------- /templates/__gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .sass-cache 3 | /dist 4 | .tmp 5 | /public 6 | .offline -------------------------------------------------------------------------------- /templates/src/js/common.js: -------------------------------------------------------------------------------- 1 | require('./common/global.js'); 2 | require('./common/report.js'); 3 | -------------------------------------------------------------------------------- /templates/src/test-include.html: -------------------------------------------------------------------------------- 1 | conctent here 2 | 3 | 4 | -------------------------------------------------------------------------------- /components/sprite/sprite.scss: -------------------------------------------------------------------------------- 1 | $<%= spriteName %>-layout:smart; 2 | @import "sprite/<%= spriteName %>/*.png"; 3 | -------------------------------------------------------------------------------- /components/sprite/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/components/sprite/icon.png -------------------------------------------------------------------------------- /templates/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/favicon.ico -------------------------------------------------------------------------------- /templates/src/css/common/_level.scss: -------------------------------------------------------------------------------- 1 | $level-layout:smart; 2 | @import"sprite/level/*.png"; 3 | @include all-level-sprites; 4 | -------------------------------------------------------------------------------- /templates/src/js/common/global.js: -------------------------------------------------------------------------------- 1 | // keep it if using url md5 rev replacement in javascript 2 | console.log('global is load'); 3 | -------------------------------------------------------------------------------- /templates/src/img/common/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/common/banner.png -------------------------------------------------------------------------------- /templates/src/img/sprite/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/icons/search.png -------------------------------------------------------------------------------- /templates/src/img/sprite/icons/webqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/icons/webqq.png -------------------------------------------------------------------------------- /templates/src/img/sprite/level/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/level/search.png -------------------------------------------------------------------------------- /templates/src/img/sprite/level/webqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/level/webqq.png -------------------------------------------------------------------------------- /templates/src/img/sprite/icons@2x/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/icons@2x/search.png -------------------------------------------------------------------------------- /templates/src/img/sprite/icons@2x/webqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/sprite/icons@2x/webqq.png -------------------------------------------------------------------------------- /templates/src/img/static/static-img-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rehorn/slush-alloyteam-simple/HEAD/templates/src/img/static/static-img-url.png -------------------------------------------------------------------------------- /templates/userdef.js: -------------------------------------------------------------------------------- 1 | // user custom file 2 | // don't submit to svn/git 3 | module.exports = { 4 | distId: 'R000567', 5 | opUser: 'rehorn' 6 | }; 7 | -------------------------------------------------------------------------------- /components/sprite/autosprite.scss: -------------------------------------------------------------------------------- 1 | $<%= spriteName %>-layout:smart; 2 | @import "sprite/<%= spriteName %>/*.png"; 3 | @include all-<%= spriteName %>-sprites; 4 | -------------------------------------------------------------------------------- /templates/src/html/master.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /templates/src/tpl/index/list.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | include ../common/header.jade 4 | body 5 | h1 #{body} 6 | p Welcome to my super lame site. 7 | include ../common/footer.jade -------------------------------------------------------------------------------- /templates/__editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /templates/src/test-extend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | my content 6 |
7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | coverage 7 | *.orig 8 | .idea 9 | sandbox 10 | test/out-fixtures/* 11 | test/watch-*.txt 12 | templates/node_modules 13 | templates/.sass-cache 14 | templates/dist/* 15 | templates/.tmp 16 | templates/public/* 17 | templates/.offline -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | coverage 7 | *.orig 8 | .idea 9 | sandbox 10 | test/out-fixtures/* 11 | test/watch-*.txt 12 | templates/node_modules 13 | templates/.sass-cache 14 | templates/dist/* 15 | templates/.tmp 16 | templates/public/* 17 | templates/.offline -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | Alloyteam Simple Web Apps 2 | ========================== 3 | 4 | alloyteam web 前端项目工程化模板 5 | 6 | ### 安装 7 | 1. 安装 npm 依赖 (或直接下载 node_modules.zip解压) 8 | ```javascript 9 | npm install 10 | ``` 11 | 2. 开发 12 | ```javascript 13 | gulp 14 | ``` 15 | 3. 编译发布 16 | ```javascript 17 | gulp dist 18 | ``` -------------------------------------------------------------------------------- /templates/src/js/index.js: -------------------------------------------------------------------------------- 1 | require('./common/global.js'); 2 | 3 | var list = require('../tpl/index/list.jade'); 4 | 5 | var data = { 6 | body: 'this is body', 7 | title: 'hi title' 8 | }; 9 | var dom = list(data); 10 | document.write(dom); 11 | 12 | console.log('test!!'); 13 | console.log('index loaded'); 14 | -------------------------------------------------------------------------------- /components/page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= pageName %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /templates/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Index Demo Page 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/__jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "camelcase": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "forin": true, 6 | "indent": 4, 7 | "latedef": true, 8 | "newcap": true, 9 | "trailing": true, 10 | 11 | "undef": true, 12 | "predef": [ "$" ], 13 | 14 | "boss": true, 15 | "expr": true, 16 | "sub": true, 17 | 18 | "maxerr": 100, 19 | "jquery": true, 20 | "browser": true 21 | } -------------------------------------------------------------------------------- /templates/src/css/index.scss: -------------------------------------------------------------------------------- 1 | @charset"UTF-8"; 2 | @import"common/level"; 3 | @import"common/ricons"; 4 | @import"common/reset"; 5 | body { 6 | border: 1; 7 | } 8 | .hello { 9 | &:before { 10 | @include level-sprite("search"); 11 | } 12 | } 13 | .hello-2x { 14 | &:before { 15 | @include icons-sprite-retina("search"); 16 | } 17 | } 18 | .banner { 19 | width: 45px; 20 | height: 100px; 21 | background-image: image-url("common/banner.png"); 22 | } 23 | .test { 24 | color: red; 25 | } 26 | -------------------------------------------------------------------------------- /templates/project.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // 站点相关,项目名 3 | name: '<%= name %>', 4 | // 项目 cdn 根,对应 alloydist 发布系统的 public/cdn/ 5 | cdn: '<%= cdn %>', 6 | // 项目 html 根,对应 alloydist 发布系统的 public/webserver/ 7 | webServer: '<%= webServer %>', 8 | // 子模块名称 9 | subModule: '<%= subModule %>', 10 | // 是否开启 liveproxy 11 | liveproxy: 1, 12 | // 发布单号,用于命令行发布 13 | distId: '', 14 | // jb 发布映射设置建议,不需改动 15 | distHtmlDir: '<%= distHtmlDir %>', // html映射 16 | distCdnDir: '<%= distCdnDir %>' // cdn映射 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slush-alloyteam-simple", 3 | "version": "0.7.0", 4 | "description": "Alloyteam Simple Web Apps generator base on slush & glup", 5 | "keywords": [ 6 | "slushgenerator", "gulp", "web", "app", "front-end", "node", "alloyteam", "simple" 7 | ], 8 | "homepage": "https://github.com/rehorn/slush-alloyteam-simple", 9 | "bugs": "https://github.com/rehorn/slush-alloyteam-simple/issues", 10 | "author": "rehornchen@tencent.com", 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/rehorn/slush-alloyteam-simple.git" 14 | }, 15 | "main": "slushfile.js", 16 | "files": [ 17 | "slushfile.js", 18 | "templates", 19 | "components" 20 | ], 21 | "engines": { 22 | "node": ">= 0.8.0", 23 | "npm": ">=1.0.0" 24 | }, 25 | "dependencies": { 26 | "gulp": "^3.8.6", 27 | "gulp-install": "^0.1.8", 28 | "gulp-template": "^0.1.1", 29 | "gulp-util": "^2.2.20", 30 | "gulp-if": "^1.2.2", 31 | "gulp-rename": "^1.2.0", 32 | "inquirer": "^0.5.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /components/sprite/retina.scss: -------------------------------------------------------------------------------- 1 | $<%= spriteName %>:sprite-map("sprite/<%= spriteName %>/*.png", $layout:smart); 2 | $<%= spriteName %>-2x:sprite-map("sprite/<%= spriteName %>@2x/*.png", $layout:smart); 3 | //Sprite mixin, works perfectly with standard defines 4 | @mixin <%= spriteName %>-sprite-retina($sprite) { 5 | background-image: sprite-url($<%= spriteName %>); 6 | background-position: sprite-position($<%= spriteName %>, $sprite); 7 | background-repeat: no-repeat; 8 | overflow: hidden; 9 | display: block; 10 | height: image-height(sprite-file($<%= spriteName %>, $sprite)); 11 | width: image-width(sprite-file($<%= spriteName %>, $sprite)); 12 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 13 | background-image: sprite-url($<%= spriteName %>-2x); 14 | background-size: (image-width(sprite-path($<%= spriteName %>-2x)) / 2) (image-height(sprite-path($<%= spriteName %>-2x)) / 2); 15 | background-position: round(nth(sprite-position($<%= spriteName %>-2x, $sprite), 1) / 2) round(nth(sprite-position($<%= spriteName %>-2x, $sprite), 2) / 2); 16 | height: image-height(sprite-file($<%= spriteName %>-2x, $sprite)) / 2; 17 | width: image-width(sprite-file($<%= spriteName %>-2x, $sprite)) / 2; 18 | } 19 | } -------------------------------------------------------------------------------- /templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alloyteam-simple", 3 | "version": "0.1.1", 4 | "description": "Alloyteam Simple Web Apps - By Slush generator alloyteam-simple", 5 | "keywords": [ 6 | "front-end", 7 | "alloyteam", 8 | "web", 9 | "app" 10 | ], 11 | "homepage": "https://github.com/alloyteam", 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/rehorn/slush-alloyteam-simple.git" 15 | }, 16 | "author": "alloyteam", 17 | "dependencies": {}, 18 | "devDependencies": { 19 | "async": "^2.0.1", 20 | "babel-core": "^6.13.2", 21 | "babel-loader": "^6.2.4", 22 | "babel-preset-es2015": "^6.13.2", 23 | "babel-preset-es2015-loose": "^7.0.0", 24 | "del": "^2.2.1", 25 | "ejs-compiled-loader": "^2.1.1", 26 | "file-loader": "^0.9.0", 27 | "file2-loader": "^0.1.0", 28 | "gulp": "^3.9.1", 29 | "gulp-clean-css": "^2.0.12", 30 | "gulp-compass": "^2.1.0", 31 | "gulp-html-extend": "^1.1.6", 32 | "gulp-htmlrefs": "^0.3.6", 33 | "gulp-if": "^2.0.1", 34 | "gulp-minify-html": "^1.0.6", 35 | "gulp-newer": "^1.2.0", 36 | "gulp-rev": "^7.1.0", 37 | "gulp-savefile": "^0.1.1", 38 | "gulp-uglify": "^2.0.0", 39 | "gulp-zip": "^3.2.0", 40 | "jade": "^1.11.0", 41 | "jade-loader": "^0.8.0", 42 | "liveproxy": "^0.1.4", 43 | "lodash": "^4.14.2", 44 | "request": "^2.74.0", 45 | "run-sequence": "^1.2.2", 46 | "style-loader": "^0.13.1", 47 | "vinyl-paths": "^2.1.0", 48 | "webpack-stream": "^3.2.0" 49 | }, 50 | "engines": { 51 | "node": ">=0.10.0", 52 | "npm": ">=1.2.10" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /templates/config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # set the css file encoding 4 | Encoding.default_external = "utf-8" 5 | 6 | dist_root = "dist/" 7 | http_images_path = "../img/common" 8 | http_generated_images_path = "../../img" 9 | generated_images_dir = dist_root + "img" 10 | 11 | # To enable relative paths to assets via compass helper functions. Uncomment: 12 | # relative_assets = true 13 | 14 | # To disable debugging comments that display the original location of your selectors. Uncomment: 15 | # line_comments = false 16 | 17 | # cache buster via parameter 18 | # Increment the deploy_version before every release to force cache busting. 19 | # deploy_version = 1 20 | # asset_cache_buster do |http_path, real_path| 21 | # if File.exists?(real_path) 22 | # hash = Digest::MD5.file(real_path.path).hexdigest 23 | # hash.to_s[0, 8] 24 | # else 25 | # "v=#{deploy_version}" 26 | # end 27 | # end 28 | 29 | # cache buster via path md5 30 | asset_cache_buster do |path, real_path| 31 | if File.exists?(real_path) 32 | pathname = Pathname.new(path) 33 | hash = Digest::MD5.file(real_path.path).hexdigest 34 | hash = hash.to_s[0, 8] 35 | new_path = "%s/%s-%s%s" % [http_images_path, pathname.basename(pathname.extname), hash, pathname.extname] 36 | 37 | {:path => new_path, :query => nil} 38 | end 39 | end 40 | 41 | # If you prefer the indented syntax, you might want to regenerate this 42 | # project again passing --syntax sass, or you can uncomment this: 43 | # preferred_syntax = :sass 44 | # and then run: 45 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 46 | -------------------------------------------------------------------------------- /templates/livefile.js: -------------------------------------------------------------------------------- 1 | var express = require('liveproxy').express; 2 | 3 | // mocker cgi 路由模拟 4 | // function log(req) { 5 | // console.log('[mocker]: ' + req.url); 6 | // }; 7 | 8 | // var router1 = express.Router(); 9 | // router1.get('/v1/post/:id', function(req, res, next) { 10 | // log(req); 11 | // res.end('v1 called'); 12 | // }); 13 | 14 | module.exports = { 15 | // action 上下文目录 16 | cwd: './dist', 17 | 18 | // 外网访问代理 19 | // proxyAgent: 'proxy.tencent.com:8080', 20 | 21 | // 本地文件夹替换配置 22 | handler: [{ 23 | match: '<%= webServerResolve %>index.html', 24 | action: './' 25 | }, { 26 | match: '<%= webServerResolve %>', 27 | action: './' 28 | }, { 29 | match: '<%= cdnResolve %>', 30 | action: './' 31 | }], 32 | 33 | // cgi mocker 模拟配置 34 | // mocker: [{ 35 | // match: 'cgi.find.qq.com', 36 | // action: router1 37 | // }], 38 | 39 | // host/路由配置 40 | // router: [{ 41 | // match: 'find.qq.com/cgi-bin/', 42 | // action: '-' 43 | // }, { 44 | // match: 'find.qq.com/', 45 | // action: '10.12.23.156:8080' 46 | // }], 47 | 48 | // 扩展配置,目前支持 [网络延迟delay], [添加response返回头addResponseHeader] 49 | // extender: [{ 50 | // match: 'find.qq.com/cgi-bin/', 51 | // action: { 52 | // func: 'delay', 53 | // args: 5 54 | // } 55 | // }, { 56 | // match: 'find.qq.com/', 57 | // action: { 58 | // func: 'addResponseHeader', 59 | // args: ['powered', 'alloyteam'] 60 | // } 61 | // }] 62 | }; 63 | -------------------------------------------------------------------------------- /components/project.example.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // 站点相关,项目名 3 | name: 'alloyteam-simple-app', 4 | // 项目 cdn 根,对应 alloydist 发布系统的 public/cdn/ 5 | cdn: 'http://s.url.cn/qqfind/', 6 | // 项目 html 根,对应 alloydist 发布系统的 public/webserver/ 7 | webServer: 'http://find.qq.com/', 8 | // 子模块名称 9 | subMoudle: '/', 10 | // webpack: js 模块化相关 11 | webpack: { 12 | entry: { 13 | index: './src/js/index/index.js' 14 | }, 15 | output: { 16 | filename: '[name].js', 17 | }, 18 | externals: { 19 | jQuery: "jQuery" 20 | }, 21 | module: { 22 | loaders: [{ 23 | test: /\.hbs$/, 24 | loader: "handlebars-loader" 25 | }] 26 | } 27 | }, 28 | // jb 相关配置 29 | // offline: { 30 | // 'bid': 128, // alloykit bid, 需要修改 31 | // 'publish': true, 32 | // 'compatible': 0, 33 | // 'qversionfrom': 0, 34 | // 'qversionto': 0, 35 | // 'platform': [2, 3], 36 | // 'loadmode': 2, 37 | // 'verifyType': 0, 38 | // 'expire_time': 1577836800000, 39 | // 'cdn': 'defaultCDN', 40 | // 'note': '', 41 | // 'frequency': 1, 42 | // 'gray': true, 43 | // 'uins': [] 44 | // }, 45 | // 可选,jb 部署单号,用于命令行操作 46 | distId: '', 47 | // 操作用户 48 | opUser: 'alloy-gulp', 49 | // 接口校验 token 50 | token: 'ASdxseRTSXfiGUIxnuRisTU', 51 | // jb 发布映射设置建议,不需改动 52 | distHtmlDir: '/data/sites/find.qq.com/', // html映射 53 | distCdnDir: '/data/sites/cdn.qplus.com/qqfind/' // cdn映射 54 | }; 55 | -------------------------------------------------------------------------------- /templates/src/css/common/_ricons.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Retina Sprites for Compass 3 | * by: Gaya Kessler 4 | * last update: 03/11/14 5 | * 6 | * Usage: 7 | * 1. create two folders in your image directory (in this case 'icons' and 'icons-2x'). 8 | * 2. adjust the foldernames defined below if you use different names. 9 | * 3. create sprite images for pixel ratio 1 screens and put them in the first folder. 10 | * 4. create sprite images for pixel ratio 2 screens and put them in the second folder, use the same filenames. 11 | * 5. use the sprite-image in your Sass/Scss using: '@include use-sprite()' 12 | */ 13 | 14 | //first we'll define the folders where the sprites are and their layouts 15 | $icons:sprite-map("sprite/icons/*.png", $layout:smart); 16 | $icons-2x:sprite-map("sprite/icons@2x/*.png", $layout:smart); 17 | //Sprite mixin, works perfectly with standard defines 18 | @mixin icons-sprite-retina($sprite) { 19 | background-image: sprite-url($icons); 20 | background-position: sprite-position($icons, $sprite); 21 | background-repeat: no-repeat; 22 | overflow: hidden; 23 | display: block; 24 | height: image-height(sprite-file($icons, $sprite)); 25 | width: image-width(sprite-file($icons, $sprite)); 26 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 27 | background-image: sprite-url($icons-2x); 28 | background-size: (image-width(sprite-path($icons-2x)) / 2) (image-height(sprite-path($icons-2x)) / 2); 29 | background-position: round(nth(sprite-position($icons-2x, $sprite), 1) / 2) round(nth(sprite-position($icons-2x, $sprite), 2) / 2); 30 | height: image-height(sprite-file($icons-2x, $sprite)) / 2; 31 | width: image-width(sprite-file($icons-2x, $sprite)) / 2; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /templates/src/css/common/_reset.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | li { 9 | list-style: none; 10 | } 11 | 12 | input[type=search] { 13 | -webkit-appearance: none; 14 | } 15 | 16 | a { 17 | text-decoration: none; 18 | color: #0079ff; 19 | } 20 | 21 | html { 22 | width: 100%; 23 | background: #f8f8f8; 24 | font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif; 25 | min-height: 100%; 26 | display: -webkit-flex; 27 | display: flex; 28 | } 29 | html body { 30 | width: 100%; 31 | max-width:800px; 32 | margin:0 auto; 33 | background: #f8f8f8; 34 | -webkit-touch-callout: none; 35 | -webkit-user-select: none; 36 | -webkit-user-drag: none; 37 | min-height: 100%; 38 | -webkit-flex: 1; 39 | flex: 1; 40 | display: -webkit-flex; 41 | display: flex; 42 | -webkit-flex-direction: column; 43 | flex-direction: column; 44 | overflow-x: hidden; 45 | overflow-y: auto; 46 | } 47 | 48 | .hide { 49 | display: none; 50 | } 51 | a, img, input, textarea, button { 52 | -webkit-touch-callout: none; 53 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 54 | border-radius: 0; 55 | -webkit-border-radius: 0; 56 | /* 57 | appearance: none; 58 | -webkit-appearance: none; 59 | */ 60 | outline: none; 61 | 62 | &:active, &:focu { 63 | outline: none; 64 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 65 | } 66 | } 67 | 68 | .nohighlight { 69 | -webkit-touch-callout: none; 70 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 71 | } 72 | 73 | .section-1px { 74 | position: relative; 75 | &:before, &:after { 76 | border-top: 1px solid #c8c7cc; 77 | content: ' '; 78 | display: block; 79 | width: 100%; 80 | position: absolute; 81 | left: 0; 82 | pointer-events: none; 83 | } 84 | &::before { 85 | top: -1px; 86 | } 87 | &::after { 88 | bottom: -1px; 89 | } 90 | } 91 | 92 | .border-1px { 93 | position: relative; 94 | &::after { 95 | content: ' '; 96 | display: block; 97 | width: 100%; 98 | height: 100%; 99 | position: absolute; 100 | border: 1px solid #c8c7cc; 101 | top: 0; 102 | left: 0; 103 | pointer-events: none; 104 | } 105 | } 106 | 107 | @media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) { 108 | .section-1px { 109 | &::after, &::before { 110 | -webkit-transform: scaleY(.7); 111 | -webkit-transform-origin: 0 0; 112 | transform: scaleY(.7); 113 | } 114 | &::after { 115 | -webkit-transform-origin: left bottom; 116 | } 117 | } 118 | } 119 | 120 | @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) { 121 | .section-1px { 122 | &::after, &::before { 123 | -webkit-transform: scaleY(.5); 124 | transform: scaleY(.5); 125 | } 126 | } 127 | .border-1px { 128 | &::after { 129 | width: 200%; 130 | height: 200%; 131 | -webkit-transform: scale(.5, .5); 132 | transform: scale(.5, .5); 133 | -webkit-transform-origin: 0 0; 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /slushfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | gutil = require('gulp-util'), 3 | install = require('gulp-install'), 4 | template = require('gulp-template'), 5 | gulpif = require('gulp-if'), 6 | rename = require('gulp-rename'), 7 | path = require('path'), 8 | url = require('url'), 9 | inquirer = require('inquirer'); 10 | 11 | function isUndefined(obj) { 12 | return obj === void 0; 13 | }; 14 | 15 | function fixUrl(urlString, prefix, endfix) { 16 | if (!urlString) return '/'; 17 | endfix = isUndefined(endfix) ? true : endfix; 18 | prefix = isUndefined(prefix) ? true : prefix; 19 | if (prefix) { 20 | urlString = urlString.indexOf('http://') < 0 ? 'http://' + urlString : urlString; 21 | } 22 | if (endfix) { 23 | urlString = urlString[urlString.length - 1] == '/' ? urlString : urlString + '/'; 24 | } 25 | return urlString; 26 | }; 27 | 28 | gulp.task('default', function(done) { 29 | gutil.log('slush-alloyteam-simple'); 30 | 31 | var tplFiles = function(file) { 32 | var basename = path.basename(file.path); 33 | return (basename === 'project.js') || (basename === 'livefile.js'); 34 | }; 35 | 36 | inquirer.prompt([{ 37 | type: 'input', 38 | name: 'name', 39 | message: '项目名称 -> ' 40 | }, { 41 | type: 'input', 42 | name: 'webServer', 43 | message: '项目html路径,如: http://find.qq.com/qqun/search/ -> ' 44 | }, { 45 | type: 'input', 46 | name: 'cdn', 47 | message: '项目cdn路径,如: http://s.url.cn/qqun/qqfind/search/ -> ' 48 | }, { 49 | type: 'input', 50 | name: 'subModule', 51 | message: '子项目名字(可直接enter留空),如: 双十一活动子项目 qiqi_1111 -> ' 52 | }, { 53 | type: 'confirm', 54 | name: 'moveon', 55 | message: '开始初始化项目? -> ' 56 | }], 57 | function(answers) { 58 | if (!answers.moveon) { 59 | return done(); 60 | } 61 | 62 | if (!answers.webServer) { 63 | gutil.log('html根目录不能为空!'); 64 | return done(); 65 | } 66 | 67 | // set cdn default webserver 68 | answers.cdn = answers.cdn || answers.webServer; 69 | answers.subModule = answers.subModule || ''; 70 | 71 | // fix url 72 | answers.cdn = fixUrl(answers.cdn); 73 | answers.webServer = fixUrl(answers.webServer); 74 | answers.subModule = fixUrl(answers.subModule, false, true); 75 | 76 | // alloydist mapping setting suggestion 77 | var cdnUrlObj = url.parse(answers.cdn); 78 | var webUrlObj = url.parse(answers.webServer); 79 | answers.distCdnDir = '/data/sites/cdn.qplus.com' + cdnUrlObj.pathname; 80 | answers.distHtmlDir = '/data/sites/' + webUrlObj.hostname + webUrlObj.pathname; 81 | 82 | // for livefile.js 83 | var webServer = (answers.subModule === '/') ? answers.webServer : answers.webServer + answers.subModule; 84 | var cdn = (answers.subModule === '/') ? answers.cdn : answers.cdn + answers.subModule; 85 | answers.webServerResolve = webServer.replace('http://', ''); 86 | answers.cdnResolve = cdn.replace('http://', ''); 87 | 88 | gulp.src(__dirname + '/templates/**') 89 | .pipe(gulpif(tplFiles, template(answers))) 90 | .pipe(rename(function(file) { 91 | if (file.basename[0] === '_' && file.basename[1] === '_') { 92 | file.basename = '.' + file.basename.slice(2); 93 | } 94 | })) 95 | .pipe(gulp.dest('./')) 96 | // .pipe(install()) 97 | .on('finish', function() { 98 | done(); 99 | }); 100 | }); 101 | }); 102 | 103 | gulp.task('page', function(done) { 104 | var pageName = gulp.args[0]; 105 | if (!pageName) { 106 | console.log('page name require'); 107 | done(); 108 | return; 109 | } 110 | 111 | var data = { 112 | pageName: pageName 113 | }; 114 | gulp.src(__dirname + '/components/page/index.html') 115 | .pipe(template(data)) 116 | .pipe(rename(function(file) { 117 | file.basename = file.basename.replace('index', pageName); 118 | })) 119 | .pipe(gulp.dest('./src')); 120 | 121 | gulp.src(__dirname + '/components/page/index.js') 122 | .pipe(rename(function(file) { 123 | file.basename = file.basename.replace('index', pageName); 124 | })) 125 | .pipe(gulp.dest('./src/js/')); 126 | 127 | gulp.src(__dirname + '/components/page/index.scss') 128 | .pipe(rename(function(file) { 129 | file.basename = file.basename.replace('index', pageName); 130 | })) 131 | .pipe(gulp.dest('./src/css/')); 132 | 133 | gulp.src(__dirname + '/components/page/index.jade') 134 | .pipe(gulp.dest('./src/tpl/' + pageName + '/')); 135 | 136 | done(); 137 | }); 138 | 139 | gulp.task('autosprite', function(done) { 140 | var spriteName = gulp.args[0]; 141 | if (!spriteName) { 142 | console.log('sprite name require'); 143 | done(); 144 | return; 145 | } 146 | 147 | var data = { 148 | spriteName: spriteName 149 | }; 150 | gulp.src(__dirname + '/components/sprite/autosprite.scss') 151 | .pipe(template(data)) 152 | .pipe(rename(function(file) { 153 | file.basename = file.basename.replace('autosprite', '_' + spriteName); 154 | })) 155 | .pipe(gulp.dest('./src/css/common')); 156 | 157 | gulp.src(__dirname + '/components/sprite/icon.png') 158 | .pipe(gulp.dest('./src/img/sprite/' + spriteName + '/')); 159 | 160 | done(); 161 | }); 162 | 163 | gulp.task('sprite', function(done) { 164 | var spriteName = gulp.args[0]; 165 | if (!spriteName) { 166 | console.log('sprite name require'); 167 | done(); 168 | return; 169 | } 170 | 171 | var data = { 172 | spriteName: spriteName 173 | }; 174 | gulp.src(__dirname + '/components/sprite/sprite.scss') 175 | .pipe(template(data)) 176 | .pipe(rename(function(file) { 177 | file.basename = file.basename.replace('sprite', '_' + spriteName); 178 | })) 179 | .pipe(gulp.dest('./src/css/common')); 180 | 181 | gulp.src(__dirname + '/components/sprite/icon.png') 182 | .pipe(gulp.dest('./src/img/sprite/' + spriteName + '/')); 183 | 184 | done(); 185 | }); 186 | 187 | gulp.task('retina', function(done) { 188 | var spriteName = gulp.args[0]; 189 | if (!spriteName) { 190 | console.log('sprite name require'); 191 | done(); 192 | return; 193 | } 194 | 195 | var data = { 196 | spriteName: spriteName 197 | }; 198 | gulp.src(__dirname + '/components/sprite/retina.scss') 199 | .pipe(template(data)) 200 | .pipe(rename(function(file) { 201 | file.basename = file.basename.replace('retina', '_' + spriteName); 202 | })) 203 | .pipe(gulp.dest('./src/css/common')); 204 | 205 | gulp.src(__dirname + '/components/sprite/icon.png') 206 | .pipe(gulp.dest('./src/img/sprite/' + spriteName + '/')); 207 | 208 | gulp.src(__dirname + '/components/sprite/icon.png') 209 | .pipe(gulp.dest('./src/img/sprite/' + spriteName + '@2x/')); 210 | 211 | done(); 212 | }); 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | slush-alloyteam-simple 2 | ========================== 3 | 4 | Alloyteam Simple Web Apps generator base on slush & glup 5 | 6 | Alloyteam web 前端项目工程化模板 7 | 8 | ### 特性 9 | 1. 基于 gulp 进行构建,方便快捷,易于定制和插件支持 10 | 2. 最小化需配置项 (project.js),基于约定优于配置理念 11 | 3. 所有资源使用增量发布策略,文件名全部 md5 版本化,让产品轻松支持多版本并存 12 | 2. [css] 使用 compass 编写模块化、可维护 css 13 | 2. [css] 使用 compass 自动 sprite 生成精灵图,自动生成版本化图片 (无需修改时间戳) 14 | 3. [js] 支持多种模块化策略,使用 webpack 进行 cmd/amd 模块化打包,支持 es6 15 | 4. [js] 内置 handlebar 模板引擎支持,发布前编译 16 | 5. [html] 自动替换 html 内部资源引用路径,替换为 cdn/md5 版本化路径 17 | 6. [html] 轻松支持 js/css 资源内嵌到页面 18 | 7. [工程化集成] 生成资源(ak离线包、web资源),对接内部发布系统 jb.oa.com 19 | 7. [工程化集成] 通过 task 调用 jb.oa.com 提供 rest api 接口,轻松实现命令行部署测试环境、正式环境、离线包发布等 20 | 21 | ### 依赖 22 | 1. [ruby](https://www.ruby-lang.org/) & [compass](http://compass-style.org/) 23 | 2. [nodejs](http://nodejs.org/) 24 | 3. [gulp](https://github.com/gulpjs/gulp/) & [slush](https://github.com/slushjs/slush) 25 | 26 | ### 安装 27 | * 安装 ruby,参考 https://www.ruby-lang.org/en/installation/ 28 | * 建议安装 compass preview 版本 29 | ```shell 30 | gem install compass -v 1.0.1 31 | ``` 32 | * 安装 nodejs,参考 http://nodejs.org/ 33 | * 安装 gulp slush slush-alloyteam-simple 34 | ```shell 35 | npm install -g gulp slush slush-alloyteam-simple 36 | ``` 37 | * 创建项目目录 38 | ```shell 39 | mkdir alloyteam-webapp 40 | cd alloyteam-webapp 41 | ``` 42 | * 初始化项目 43 | ```shell 44 | slush alloyteam-simple 45 | ``` 46 | * 按照提示填写项目初始化信息 47 | ```shell 48 | 项目名称,如:alloyteam-webapp 49 | 项目html路径,如:http://find.qq.com/qqun/search/ 50 | 项目cdn路径,如:http://s.url.cn/qqun/qqfind/search/ 51 | 子项目(可留空),如:qiqi_1111 52 | ``` 53 | * [可选] 确定 jb.oa.com 是否有对应部署映射,多个子项目的映射可以公用,如各种运营活动,activity/qiqi_1111 54 | ```shell 55 | 项目路径 与 jb 映射对应关系 56 | http://find.qq.com/qqun/search/ <=> /data/sites/find.qq.com/qqun/search/ 57 | http://s.url.cn/qqun/qqfind/search/ <=> /data/sites/cdn.qplus.com/qqun/search/ 58 | ``` 59 | * 安装构建依赖 60 | ```shell 61 | npm install 62 | ``` 63 | * 启动开发任务 64 | ```shell 65 | gulp 66 | ``` 67 | * 启动正常发布编译任务 68 | ```shell 69 | gulp dist 70 | ``` 71 | 72 | ### 目录约定 73 | * 根目录 74 | ```shell 75 | ./alloyteam-simple-app/ 76 | ├── README.md 77 | ├── config.rb -- sass 配置文件,不需修改 78 | ├── dist -- 开发编译目录,开发时将资源替换到这里 79 | ├── gulpfile.js -- gulp 构建文件,不需修改,版本升级,只需下载最新覆盖 80 | ├── livefile.js -- liveproxy 配置文件,用于本地开发代理 81 | ├── node_modules 82 | ├── package.json 83 | ├── project.js -- 全局配置 84 | ├── src -- 源代码目录 85 | └── userdef.js -- jb.oa.com 发布系统集成配置文件 86 | ``` 87 | * 源代码目录 88 | ```shell 89 | ./src 90 | ├── css -- sass 样式目录,不需要编译生成 .css 文件的子模块,请使用 _ 开头 91 | │   ├── common -- 公共样式 92 | │   │   ├── _level.scss -- 自动 sprite 合并图片示范 93 | │   │   ├── _reset.scss -- reset css 公共模块 94 | │   │   └── _ricons.scss -- retina 高清 sprite 合并图片示范 95 | │   ├── index -- index 页面样式子模块,可以将 index 所需样式进行子模块划分,便于管理 96 | │   │   └── _submodule.scss -- 子模块,以下划线开头 97 | │   │   └── index.scss -- 合并所有 index 页面样式子模块,公共模块,合图... 98 | ├── favicon.ico 99 | ├── img -- 图片目录 100 | │   ├── common -- 不需合图的图片,文件会自动在文件名加上md5,filename-md5.png 101 | │   │   ├── banner.png -- 自动生成 banner-be70f3b1.png 102 | │   ├── sprite -- 需要合图的图片,安装生成 sprite 图片名进行目录划分,可以自己新建子目录 103 | │   │   ├── icons -- 普清图,最终合并生成 icons-sbb41937c32.png 104 | │   │   ├── icons@2x -- 2x高清图,生成 icons@2x-sb721890e87.png 105 | │   │   └── level -- 普清图,生成 level-s99b1a493c7.png 106 | │   └── static -- 不需合图的图片,不需自动md5重命名的图片 107 | │   ├── static-img-url.png 108 | ├── index.html -- 首页 109 | ├── js -- js 目录,使用 cmd require 规范进行模块之间应用 110 | │   ├── common -- 公共模块 111 | │   │   ├── config.js 112 | │   │   └── global.js 113 | │   ├── index -- 首页 js 模块 114 | │   │   └── index.js 115 | │   └── libs -- 第三方 js 库,会被复制到 dist 目录,js/css 文件名 md5 化 116 | │   └── jquery 117 | ├── libs -- 第三方库,libs 所有文件会被复制到 dist 目录,js/css 文件名 md5 化 118 | │   └── bootstrap 119 | │   ├── bootstrap.css 120 | │   └── bootstrap.js 121 | └── tpl -- handlebar 模板文件 122 | ├── common -- 公共模板页面片 123 | │   ├── footer.hbs 124 | │   └── header.hbs 125 | └── index -- 首页模板 126 | └── list.hbs 127 | ``` 128 | 129 | ### 如何新建一个页面,如下:mypage 为需要创建的页面名称 130 | ``` 131 | slush alloyteam-simple:page mypage 132 | ``` 133 | 将会生成如下目录和文件 134 | ``` 135 | ./src 136 | ├── mypage.html 137 | ├── css 138 | │   ├── mypage 139 | │   │   └── _index.scss 140 | │   └── mypage.scss 141 | ├── js 142 | │   ├── mypage 143 | │   │   └── index.js 144 | ├── tpl 145 | │   ├── mypage 146 | │   │   └── index.hbs 147 | ``` 148 | 修改 project.js 中的 webpack entry 项目,添加对应的 js 编译项 149 | ``` 150 | entry: { 151 | index: './src/js/index/index.js', 152 | mypage: './src/js/mypage/index.js' 153 | }, 154 | ``` 155 | 156 | ### 如何新建一个 sprite 自动合图,如下:mysprite 为需要创建的 sprite 名称 157 | ``` 158 | # 生成精灵图,方式一:自动生成合图样式,参考下面【关于 css】说明 159 | slush alloyteam-simple:autosprite mysprite 160 | # 生成精灵图,方式二:使用 include 引用合图样式 161 | slush alloyteam-simple:sprite mysprite 162 | # 生成高清精灵图 163 | slush alloyteam-simple:retina mysprite 164 | ``` 165 | 将会生成如下目录和文件 166 | ``` 167 | ./src 168 | ├── css 169 | │   ├── common 170 | │   │   └── _mysprite.scss 171 | ├── img 172 | │   ├── mysprite 173 | ``` 174 | 175 | #### project.js 配置说明 176 | ``` 177 | 待续 178 | ``` 179 | 180 | #### livefile.js 配置说明 181 | ``` 182 | 待续 183 | ``` 184 | 185 | #### userdef.js 配置说明 186 | ``` 187 | 待续 188 | ``` 189 | 190 | #### 如何开始编码 191 | 启动开发命令 192 | ```shell 193 | gulp dev 194 | ``` 195 | 196 | #### 关于 css 197 | * 使用 sass 进行 css 编写,有利于模块化,可复用 198 | * 利用 compass 提供了便捷的自动合图,只支持 png 199 | 200 | ##### 如何进行自动合图,方式一:自动生成合图样式 201 | * 在 src/img/sprite 下新建目录,名称为 sprite 名称,如QQ等级,level 202 | * 将需要合图的图片放到 img/sprite/level 下,如 search.png 和 webqq.png 203 | * 在 src/css/common 下新建文件,_level.scss (ps: 将文件内容中 level 替换为自己的 sprite 名称) 204 | ``` 205 | $level-layout:smart; 206 | @import"sprite/level/*.png"; 207 | @include all-level-sprites; 208 | ``` 209 | 上面的代码将自动生成如下代码 210 | ``` 211 | .level-search, .level-sprite, .level-webqq { 212 | background-image: url(../img/sprite/level-s99b1a493c7.png); 213 | background-repeat: no-repeat 214 | } 215 | .level-search { 216 | background-position: 0 0 217 | } 218 | .level-webqq { 219 | background-position: 0 -24px 220 | } 221 | ``` 222 | * 将对应的 css 样式规则加在 html 页面或 hbs 模板中 223 | ``` 224 | 225 | ``` 226 | 227 | ##### 如何进行自动合图,方式二:使用 include 引用合图样式 228 | * 在 src/img/sprite 下新建目录,名称为 sprite 名称,如QQ等级,level 229 | * 将需要合图的图片放到 img/sprite/level 下,如 search.png 和 webqq.png 230 | * 在 src/css/common 下新建文件,_level.scss (ps: 将文件内容中 level 替换为自己的 sprite 名称) 231 | ``` 232 | $level-layout:smart; 233 | @import"sprite/level/*.png"; 234 | ``` 235 | * 在需要引用小图标的地方,使用 @include {合图名称}-sprite("图标名称") 的方式引用 236 | ``` 237 | @import"common/level"; 238 | .hello { 239 | &:before { 240 | @include level-sprite("search"); 241 | } 242 | } 243 | ``` 244 | 上面的代码将自动生成如下代码 245 | ``` 246 | .hello:before { 247 | background-image: url(../img/sprite/level-s99b1a493c7.png); 248 | background-repeat: no-repeat 249 | } 250 | .hello:before { 251 | background-position: 0 0 252 | } 253 | ``` 254 | 255 | ##### 如何让合图支持 retina 高清屏 256 | * 大致过程参考上文 【如何进行自动合图,方式二】 257 | * 在 src/img/sprite 下新建目录,名称为 sprite 名称,如QQ等级,level 258 | * 分别在 src/img/sprite/level,src/img/sprite/level@2x 下面放普通图标和2x高清图 259 | * 在 src/css/common 下新建文件,_level.scss (ps: 将文件内容中 level 替换为自己的 sprite 名称) 260 | ``` 261 | $level:sprite-map("sprite/level/*.png", $layout:smart); 262 | $level-2x:sprite-map("sprite/level@2x/*.png", $layout:smart); 263 | @mixin level-sprite-retina($sprite) { 264 | background-image: sprite-url($level); 265 | background-position: sprite-position($level, $sprite); 266 | background-repeat: no-repeat; 267 | overflow: hidden; 268 | display: block; 269 | height: image-height(sprite-file($level, $sprite)); 270 | width: image-width(sprite-file($level, $sprite)); 271 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 272 | background-image: sprite-url($level-2x); 273 | background-size: (image-width(sprite-path($level-2x)) / 2) (image-height(sprite-path($level-2x)) / 2); 274 | background-position: round(nth(sprite-position($level-2x, $sprite), 1) / 2) round(nth(sprite-position($level-2x, $sprite), 2) / 2); 275 | height: image-height(sprite-file($level-2x, $sprite)) / 2; 276 | width: image-width(sprite-file($level-2x, $sprite)) / 2; 277 | } 278 | } 279 | ``` 280 | * 在需要引用小图标的地方,使用 @include {合图名称}-retina-sprite("图标名称") 的方式引用 281 | ``` 282 | @import"common/level"; 283 | .hello { 284 | &:before { 285 | @include level-sprite-retina("search"); 286 | } 287 | } 288 | ``` 289 | 290 | ##### 如何将图片资源内嵌到 css 中,使用 inline-image 方法 291 | ``` 292 | .hello { 293 | background-image: inline-image("banner"); 294 | } 295 | ``` 296 | 297 | #### 关于 js 298 | * 在 html 中添加 js 引用 299 | ``` 300 | # 先在 project.js 中 webpack.entry 里面添加 js 引用入口 301 | webpack: { 302 | // 页面所引用 js 配置 303 | entry: { 304 | // 格式=> [js名字]: '入口路径' 305 | index: './src/js/index/index.js' 306 | } 307 | } 308 | # 在 html 中引用 309 | 310 | ``` 311 | 312 | * 利用 webpack 进行 cmd 模块打包 313 | * 在 js 中直接使用 require 即可,全部使用相对路径 314 | ``` 315 | // ./src/js/index/index.js 316 | require('../common/global.js'); 317 | require('../common/config.js'); 318 | console.log('index is loaded'); 319 | ``` 320 | 321 | * 在 js 中引用 handlebar 模板文件 322 | ``` 323 | // ./src/js/index/index.js 324 | var listTpl = require('../../tpl/index/list.hbs'); 325 | var data = { 326 | body: 'this is body', 327 | title: 'hi title' 328 | }; 329 | var dom = listTpl(data); 330 | ``` 331 | 332 | * 在 js 中引用 src/img/common 下图片 333 | ``` 334 | var banner = require('../../img/common/banner.png'); 335 | // will change to: "http://s.url.cn/qqun/img/common/banner-be70f3b1.png" 336 | ``` 337 | 338 | * 在 js 中引用 src/img/static 下图片 339 | ``` 340 | var staticImg = require('../../img/static/static-img-url.png'); 341 | // will change to: "http://s.url.cn/qqun/img/static/static-img-url.png" 342 | ``` 343 | 344 | * 在 js 中引用第三方库,如 jQuery 345 | 修改 project.js 配置,在 webpack 配置中添加 jQuery: "jQuery" (window.jQuery 可访问,其他库类似) 346 | ``` 347 | externals: { 348 | jQuery: "jQuery" 349 | } 350 | ``` 351 | 在 js 中直接添加引用 352 | ``` 353 | var jQuery = require('jQuery'); 354 | ``` 355 | 在 html 中添加 jquery 引用 356 | ``` 357 | 358 | ``` 359 | 360 | * 独立打包公共库,共享代码,避免不同页面 js 重复打包 361 | 修改 project.js 配置,添加公共库入口 common 362 | ``` 363 | entry: { 364 | commons: './src/js/common/index.js', 365 | index: './src/js/index/index.js', 366 | mypage: './src/js/mypage/index.js' 367 | }, 368 | ``` 369 | 在 common/index.js 中暴露一个全局变量 window.commons 370 | ``` 371 | // src/js/common/index.js 372 | window.commons = { 373 | sub1: require('./sub1.js'), 374 | sub2: require('./sub2.js') 375 | }; 376 | ``` 377 | 按照第三方类库的方式,引入 commons 378 | ``` 379 | externals: { 380 | commons: "commons" 381 | } 382 | ``` 383 | 在 js 中直接添加引用 384 | ``` 385 | var commons = require('commons'); 386 | ``` 387 | 在 html 中添加 commons 引用 388 | ``` 389 | 390 | 391 | ``` 392 | 393 | * 异步远程加载 js 394 | ``` 395 | // aync loading files 396 | require(['./submod1.js', './submod2.js'], function(submod1, submod2) { 397 | console.log('submod loaded'); 398 | }); 399 | ``` 400 | 401 | ### 关于 handlebar 模板文件 402 | * 语法参考: http://handlebarsjs.com/ 403 | * https://github.com/altano/handlebars-loader 404 | 405 | ### 关于 html 文件 406 | 使用 gulp-htmlrefs 对 html 进行路径替换和内嵌 407 | * 引用 css 文件 408 | ``` 409 | 410 | ``` 411 | 将被替换为 cdn+md5 文件格式,如 412 | ``` 413 | 414 | ``` 415 | * 引用 js 文件 416 | ``` 417 | 418 | ``` 419 | 将被替换为 cdn+md5 文件格式,如 420 | ``` 421 | 422 | ``` 423 | * gulp-htmlrefs 默认会自动扫描 link/scirpt/img 三种标签并自动替换 424 | * 需要额外替换 video/source/data-main/meta/a/input 等标签,需要插入额外标签 425 | ``` 426 | 427 | 428 | 429 | ``` 430 | * 将 js/css 内嵌到 html 中 431 | ``` 432 | 433 | ``` 434 | 435 | ### 关于 liveproxy 开发代理 436 | 启动开发任务后,将自动启动一个开发代理,支持如下特性: 437 | - 本地替换 438 | - cgi 模拟 439 | - 脚本注入 440 | - host 配置 441 | - 正向透明代理远程资源(本地不存在的文件) 442 | - 自动刷新页面 livereload 443 | - 远程调试控制台 jsconsole 444 | 详细参考:https://github.com/rehorn/liveproxy 445 | 446 | ##### 使用 liveproxy 进行本地替换开发 447 | * 将浏览器代理或者系统代理配置为 127.0.0.1:8090 (端口可在 livefile.js 修改) 448 | * 将 localhost;127.0.0.1 配置不使用代理 449 | * 在浏览器中打开业务页面,如 http://find.qq.com/index.html 450 | * 编辑 src 下代码,直接浏览器查看最新页面 451 | * 编辑 livefile.js 里面 mocker 配置,进行cgi本地模拟 452 | 453 | ##### 使用 liveproxy 进行移动端远程调试 454 | * 将手机网络代理设置为 127.0.0.1:8090 455 | * 在 pc 浏览器中打开调试控制台页面 http://localhost:8091 (端口可在 livefile.js 修改) 456 | * 在手机浏览器或者webview中打开页面 457 | * 手机页面日志将自动输出 pc 端控制台中 458 | 459 | ### 腾讯内部发布平台 jb.oa.com 整合 460 | * 配置单号 461 | ``` 462 | # project.js 463 | distId: 'R000012' 464 | ``` 465 | 466 | * 部署到测试环境 467 | ``` 468 | gulp test 469 | ``` 470 | 471 | 提交一个ars发布单 472 | ``` 473 | gulp ars 474 | ``` 475 | 476 | 提交一个离线包发布 477 | ``` 478 | gulp ak 479 | ``` 480 | 481 | 482 | 483 | -------------------------------------------------------------------------------- /templates/gulpfile.js: -------------------------------------------------------------------------------- 1 | // ================= 2 | // alloyteam simple project build gulpfile 3 | // author: rehornchen@tencent.com 4 | // version: 0.8.0 5 | // last update: 2016-08-11 6 | // created: 2014-07-15 7 | // history: 8 | // 0.8.0 2016-08-11 update dependencies version & add babel-loader 9 | // 0.7.0 2015-01-11 jade/ejs support, html extend support 10 | // 0.6.1 2014-12-01 add liveproxy support 11 | // 0.5.0 2014-11-24 refact: js modular with webpack 12 | // 0.4.2 2014-10-2 add jsrefs debug support 13 | // 0.4.1 2014-09-30 add cmd line publish support 14 | // 0.3.17 2014-09-30 add retina sprite support 15 | // 0.3.16 2014-09-29 remove requirement of build:htmlrefs comment 16 | // 0.3.0 2014-07-17 adapt to slush generator 17 | // 0.2.0 2014-07-15 support htmlrefs rev alloykit-offline 18 | // 0.1.0 2014-07-15 init 19 | // -------------------- 20 | // 不要修改以下内容 21 | // ================= 22 | var gulp = require('gulp'); 23 | var runSequence = require('run-sequence'); 24 | 25 | var fs = require('fs'); 26 | var path = require('path'); 27 | var url = require('url'); 28 | var exec = require('child_process').exec; 29 | var _ = require('lodash'); 30 | var async = require('async'); 31 | var request = require('request'); 32 | var del = require('del'); 33 | var vinylPaths = require('vinyl-paths'); 34 | var liveproxy = require('liveproxy'); 35 | 36 | var compass = require('gulp-compass'), 37 | rev = require('gulp-rev'), 38 | uglify = require('gulp-uglify'), 39 | cleanCSS = require('gulp-clean-css'), // replace gulp-minify-css to gulp-clean-css 40 | // imagemin = require('gulp-imagemin'), 41 | minifyHtml = require('gulp-minify-html'), 42 | savefile = require('gulp-savefile'), 43 | webpack = require('webpack-stream'), 44 | htmlrefs = require('gulp-htmlrefs'), 45 | zip = require('gulp-zip'), 46 | extender = require('gulp-html-extend'), 47 | gulpIf = require('gulp-if'), 48 | newer = require('gulp-newer'); 49 | // ================= 50 | // configs 51 | // ================= 52 | var configs = { 53 | // about site global 54 | name: 'alloyteam-simple-default', 55 | cdn: 'http://s.url.cn/qqun/', 56 | webServer: 'http://find.qq.com/', 57 | subModule: '/', 58 | 59 | // path 相关 60 | src: './src/', 61 | dist: './dist/', 62 | deploy: './public/', 63 | 64 | // 路径配置 65 | // css: './css/', 66 | // js: './js/', 67 | // tpl: './tpl/', 68 | // img: './img/', 69 | // libs: './libs/', 70 | 71 | // webpack 72 | webpack: {}, 73 | 74 | // liveproxy 75 | liveproxy: 1, 76 | 77 | // 图片格式 78 | // imgType: '*.{jpg,jpeg,png,bmp,gif,ttf,ico,htc}', 79 | imgType: '*.*', 80 | 81 | // compress related 82 | minifyHtml: 0, 83 | minifyImage: 0, 84 | 85 | // jb support 86 | JBSupport: 1, 87 | 88 | JB_URL: 'http://fakeurl.com', 89 | 90 | ARS_URL: 'http://fake2url.com', 91 | 92 | // 使用发布离线包 93 | offline: { 94 | // 'bid': 128, // alloykit bid, 需要修改 95 | // 'publish': true, 96 | // 'compatible': 0, 97 | // 'qversionfrom': 0, 98 | // 'qversionto': 0, 99 | // 'platform': [2, 3], 100 | // 'loadmode': 2, 101 | // 'verifyType': 0, 102 | // 'expire_time': 1577836800000, 103 | // 'cdn': 'defaultCDN', 104 | // 'note': '', 105 | // 'frequency': 1, 106 | // 'gray': true, 107 | // 'uins': [] 108 | }, 109 | // 是否需要打 zip 包 110 | zip: 1, 111 | // zip 包路径配置 112 | zipConf: [], 113 | // zip 名称 114 | zipName: 'offline.zip', 115 | // 离线包黑名单 116 | zipBlacklist: [], 117 | // jb cli 发布相关,发布单号,用于命令行发布 118 | distId: '', 119 | opUser: 'alloy-gulp', 120 | token: 'ASdxseRTSXfiGUIxnuRisTU' 121 | }; 122 | 123 | // internal tmp path related 124 | var _path = { 125 | offlineCache: './.offline/', 126 | tmp: './.tmp/', 127 | cssRev: './.tmp/.cssrev/', 128 | jsRev: './.tmp/.jsrev/', 129 | }; 130 | 131 | // overwrite configs 132 | var projectConfig = require('./project') || {}; 133 | projectConfig.webpack = projectConfig.webpack || {}; 134 | var isWebpackEntry = projectConfig.webpack.entry ? true : false; 135 | _.extend(configs, _path, projectConfig); 136 | 137 | // overwrite user define value 138 | if (fs.existsSync('./userdef.js')) { 139 | _.extend(configs, require('./userdef') || {}); 140 | } 141 | 142 | // prepare root with subModule case 143 | configs.cdnRoot = (configs.subModule === '/') ? configs.cdn : configs.cdn + configs.subModule; 144 | configs.webServerRoot = (configs.subModule === '/') ? configs.webServer : configs.webServer + configs.subModule; 145 | 146 | // global vars 147 | var src = configs.src, 148 | dist = configs.dist, 149 | tmp = configs.tmp, 150 | deploy = configs.deploy, 151 | offlineCache = configs.offlineCache; 152 | 153 | // default src folder options 154 | var opt = { 155 | cwd: src, 156 | base: src 157 | }; 158 | var distOpt = { 159 | cwd: dist, 160 | base: dist 161 | }; 162 | 163 | // dev watch mode 164 | var isWatching = false; 165 | var isWebpackInit = false; 166 | 167 | // set default alloykit offline zip config 168 | var globCdn = ['**/*.*', '!**/*.{html,ico}']; 169 | var globWebServer = ['**/*.{html,ico}']; 170 | if (configs.zip && _.isEmpty(configs.zipConf)) { 171 | configs.zipConf = [{ 172 | target: configs.cdnRoot, 173 | include: globCdn 174 | }, { 175 | target: configs.webServerRoot, 176 | include: globWebServer 177 | }]; 178 | 179 | if (!_.isEmpty(configs.zipBlacklist)) { 180 | // prefix '!' to exclude 181 | _.map(configs.zipBlacklist, function(item) { 182 | return '!' + item; 183 | }); 184 | // union 185 | _.each(configs.zipConf, function(item) { 186 | _.union(item.include, configs.zipBlacklist) 187 | }); 188 | } 189 | } 190 | 191 | function initWebpackConfig() { 192 | var _cdn = isWatching ? '' : configs.cdn; 193 | var _webpack = { 194 | // cache: false, 195 | output: { 196 | // entry point dist file name 197 | filename: '[name].js', 198 | // aysnc loading chunk file root 199 | publicPath: 'js/', 200 | chunkFilename: isWatching ? 'chunk-[id].js' : 'chunk-[id]-[hash:8].js' 201 | } 202 | }; 203 | _.extend(configs.webpack, _webpack); 204 | if (isWatching) { 205 | configs.webpack.devtool = '#inline-source-map'; 206 | } else { 207 | configs.webpack.output.publicPath = configs.cdn + _webpack.output.publicPath; 208 | } 209 | 210 | _webpack.module = { 211 | loaders: [{ 212 | test: /\.js$/, 213 | loader: 'babel-loader', 214 | query: { 215 | presets: ['es2015-loose'] 216 | } 217 | },{ 218 | test: /\.jade$/, 219 | loader: 'jade-loader' 220 | }, { 221 | test: /\.ejs$/, 222 | loader: 'ejs-compiled' 223 | }, { 224 | test: /common\/.*\.(png|jpg)$/, 225 | loader: 'file2?name=' + _cdn + 'img/common/' + '[name]-[hash:8].[ext]' 226 | }, { 227 | test: /static\/.*\.(png|jpg)$/, 228 | loader: 'file2?name=' + _cdn + 'img/static/' + '[name].[ext]' 229 | }, { 230 | test: /\.css$/, 231 | loader: isWatching ? 'style/url!file?name=chunk-[name].[ext]' : 'style/url!file?name=chunk-[name]-[hash:8].[ext]' 232 | }] 233 | }; 234 | 235 | // set webpack module loader 236 | configs.webpack.module = configs.webpack.module || {}; 237 | configs.webpack.module.loaders = _webpack.module.loaders; 238 | 239 | isWebpackInit = true; 240 | }; 241 | 242 | function setWebpackEntry() { 243 | var res = [], 244 | entry = {}; 245 | // user not define entry, auto gen from js/entry folder 246 | if (!isWebpackEntry) { 247 | var folder = path.join(src, 'js'); 248 | var files = fs.readdirSync(folder); 249 | files.forEach(function(file) { 250 | var pathname = path.join(folder, file); 251 | var stat = fs.lstatSync(pathname); 252 | if (!stat.isDirectory()) { 253 | res.push(file); 254 | } 255 | }); 256 | _.each(res, function(file) { 257 | var name = path.basename(file, '.js'); 258 | entry[name] = src + 'js/' + file; 259 | }); 260 | configs.webpack.entry = entry; 261 | } 262 | }; 263 | 264 | function openBrowser(target, callback) { 265 | var map, opener; 266 | map = { 267 | 'darwin': 'open', 268 | 'win32': 'start ' 269 | }; 270 | opener = map[process.platform] || 'xdg-open'; 271 | return exec('' + opener + ' ' + target, callback); 272 | }; 273 | 274 | var customMinify = ['noop']; 275 | var customJBFlow = ['noop']; 276 | if (configs.minifyHtml) { 277 | customMinify.push('minifyHtml'); 278 | } 279 | if (configs.minifyImage) { 280 | // customMinify.push('imagemin'); 281 | } 282 | if (configs.JBSupport) { 283 | customJBFlow.push('jb:prepare'); 284 | customJBFlow.push('ak:zip'); 285 | } 286 | 287 | console.log('start to build project [' + configs.name + ']...'); 288 | 289 | // remove old or tmp files 290 | gulp.task('clean', function(cb) { 291 | del([dist, tmp, deploy, offlineCache]).then(function(paths) { 292 | cb(); 293 | }); 294 | }); 295 | 296 | // clean node_modules, fix windows file name to long bug.. 297 | gulp.task('cleanmod', function(cb) { 298 | del('./node_modules').then(function(paths) { 299 | cb(); 300 | }); 301 | }); 302 | 303 | // clean all temp files 304 | gulp.task('cleanall', function(cb) { 305 | del([dist, tmp, deploy, offlineCache, './.sass-cache']).then(function(paths) { 306 | cb(); 307 | }); 308 | }); 309 | 310 | // copy js/html from src->dist 311 | var things2copy = ['*.{html,ico}', 'libs/**/*.*', 'img/static/**/' + configs.imgType]; 312 | gulp.task('copy', function() { 313 | return gulp.src(things2copy, opt) 314 | .pipe(newer(dist)) 315 | .pipe(gulpIf('*.html', extender())) 316 | .pipe(gulp.dest(dist)); 317 | }); 318 | 319 | // copy and rev some images files [filename-md5.png style] 320 | var image2copy = '{img/,img/common/}' + configs.imgType; 321 | gulp.task('img-rev', function() { 322 | // img root 323 | return gulp.src(image2copy, opt) 324 | .pipe(newer(dist)) 325 | .pipe(rev()) 326 | .pipe(gulp.dest(dist)); 327 | }); 328 | 329 | // compile scss and auto spriting 330 | var scss2compile = '**/*.scss'; 331 | gulp.task('compass', function() { 332 | return gulp.src(scss2compile, opt) 333 | .pipe(newer(dist)) 334 | .pipe(compass({ 335 | config_file: './config.rb', 336 | css: path.join(dist, 'css'), 337 | sass: path.join(src, 'css'), 338 | image: path.join(src, 'img'), 339 | generated_image: path.join(dist, 'img/sprite') 340 | })) 341 | }); 342 | 343 | // packer js using webpack 344 | var js2webpack = src + 'js/**/*.js'; 345 | var tpl2webpack = src + 'tpl/**/*.*'; 346 | gulp.task('webpack', function() { 347 | !isWebpackInit && initWebpackConfig(); 348 | setWebpackEntry(); 349 | return gulp.src(js2webpack) 350 | .pipe(webpack(configs.webpack)) 351 | .pipe(gulp.dest(dist + 'js/')); 352 | }); 353 | 354 | // minify js and generate reversion files 355 | // stand alone cmd to make sure all js minified 356 | gulp.task('uglify', ['webpack'], function() { 357 | return gulp.src(['{' + dist + ',tmp}/**/*.js', '!' + dist + 'js/chunk-*.js']) 358 | .pipe(uglify()) 359 | .pipe(vinylPaths(del)) 360 | .pipe(rev()) 361 | .pipe(savefile()) 362 | .pipe(rev.manifest()) 363 | .pipe(gulp.dest(configs.jsRev)) 364 | }); 365 | 366 | // minify css and generate reversion files 367 | // stand alone cmd to make sure all css minified 368 | gulp.task('minifyCss', ['compass'], function() { 369 | return gulp.src(['{' + dist + ',tmp}/**/*.css', '!' + dist + 'js/chunk-*.css']) 370 | .pipe(cleanCSS()) 371 | .pipe(vinylPaths(del)) 372 | .pipe(rev()) 373 | .pipe(savefile()) 374 | .pipe(rev.manifest()) 375 | .pipe(gulp.dest(configs.cssRev)) 376 | }); 377 | 378 | // replace html/js/css reference resources to new md5 rev version 379 | // inline js to html, or base64 to img 380 | gulp.task('htmlrefs', function() { 381 | var mapping; 382 | var jsRev = configs.jsRev + 'rev-manifest.json'; 383 | var cssRev = configs.cssRev + 'rev-manifest.json'; 384 | if (fs.existsSync(jsRev) && fs.existsSync(cssRev)) { 385 | mapping = _.extend( 386 | require(jsRev), 387 | require(cssRev) 388 | ); 389 | } 390 | 391 | var refOpt = { 392 | urlPrefix: configs.cdnRoot, 393 | scope: [dist], 394 | mapping: mapping 395 | }; 396 | 397 | return gulp.src(dist + '*.html') 398 | .pipe(htmlrefs(refOpt)) 399 | .pipe(gulp.dest(dist)); 400 | }); 401 | 402 | gulp.task('minifyHtml', function() { 403 | return gulp.src(src + '*.html') 404 | .pipe(minifyHtml({ 405 | empty: true 406 | })) 407 | .pipe(savefile()); 408 | }); 409 | 410 | gulp.task('noop', function(cb) { 411 | cb(); 412 | }); 413 | 414 | // gulp.task('imagemin', function() { 415 | // return gulp.src(src + '**/' + configs.imgType) 416 | // .pipe(imagemin()) 417 | // .pipe(savefile()); 418 | // }); 419 | 420 | // jb intergration task, build files to public folder 421 | // html -> public/webserver/** cdn -> public/cdn/** 422 | gulp.task('jb:prepare', function(cb) { 423 | var deployGroup = [{ 424 | target: deploy + 'cdn/' + configs.subModule, 425 | include: globCdn 426 | }, { 427 | target: deploy + 'webserver/' + configs.subModule, 428 | include: globWebServer 429 | }]; 430 | 431 | var q = _.map(deployGroup, function(item) { 432 | return function(callback) { 433 | gulp.src(item.include, distOpt) 434 | .pipe(gulp.dest(item.target)) 435 | .on('end', function() { 436 | callback(); 437 | }); 438 | }; 439 | }); 440 | 441 | async.parallel(q, function(err, result) { 442 | cb(err, result); 443 | }); 444 | }); 445 | 446 | // prepare files to package to offline zip for alloykit 447 | gulp.task('ak:prepare', function(cb) { 448 | var q = _.map(configs.zipConf, function(item) { 449 | return function(callback) { 450 | var urlObj = url.parse(item.target); 451 | var target = path.join(offlineCache, urlObj.hostname, urlObj.pathname); 452 | gulp.src(item.include, distOpt) 453 | .pipe(gulp.dest(target)) 454 | .on('end', function() { 455 | callback(); 456 | }); 457 | }; 458 | }); 459 | 460 | async.parallel(q, function(err, result) { 461 | cb(err, result); 462 | }); 463 | }); 464 | 465 | // package .offline -> offline.zip for alloykit 466 | gulp.task('ak:zip', ['ak:prepare'], function() { 467 | return gulp.src('**/*.*', { 468 | cwd: offlineCache 469 | }) 470 | .pipe(zip(configs.zipName)) 471 | .pipe(gulp.dest(deploy + 'offline')); 472 | }); 473 | 474 | var apiData = { 475 | did: configs.distId, 476 | opUser: configs.opUser, 477 | token: configs.token 478 | }; 479 | // jb -> deloy test env 480 | gulp.task('testenv', function() { 481 | // test env 482 | request.post(configs.JB_URL + '/dist/api/go', { 483 | form: apiData 484 | }, function(err, resp, body) { 485 | var data = JSON.parse(body); 486 | console.log(data); 487 | }); 488 | }); 489 | 490 | // jb -> prebuild and create ars publish order 491 | gulp.task('ars', function() { 492 | // publish ars 493 | request.post(configs.JB_URL + '/dist/api/ars', { 494 | form: data 495 | }, function(err, resp, body) { 496 | var data = JSON.parse(body); 497 | if (data.code == 0) { 498 | var msg = JSON.parse(data.msg); 499 | if (!msg.result) { 500 | console.log('没有 ars 提单权限,请到' + configs.ARS_URL + ' 申请!'); 501 | } else { 502 | openBrowser(configs.ARS_URL + '/Rel_TestManage.htm?orderid=' + msg.releasetag + '&showend=1'); 503 | } 504 | } 505 | }); 506 | }); 507 | 508 | // jb -> prebuild and auto post offline zip 509 | gulp.task('offline', function(cb) { 510 | // publish offline zip 511 | request.post(configs.JB_URL + '/dist/api/offline', { 512 | form: data 513 | }, function(err, resp, body) { 514 | var data = JSON.parse(body); 515 | console.log(data); 516 | }); 517 | }); 518 | 519 | // support local replacement & livereload 520 | gulp.task('liveproxy', function(cb) { 521 | if (configs.liveproxy) { 522 | liveproxy({ 523 | config: './livefile.js' 524 | }); 525 | } 526 | cb(); 527 | }); 528 | 529 | gulp.task('watch:set', function() { 530 | isWatching = true; 531 | }); 532 | 533 | gulp.task('watch', function() { 534 | gulp.watch(things2copy, opt, ['copy']); 535 | gulp.watch(image2copy, opt, ['img-rev']); 536 | gulp.watch(scss2compile, opt, ['compass']); 537 | gulp.watch(js2webpack, ['webpack']); 538 | gulp.watch(tpl2webpack, ['webpack']); 539 | }); 540 | 541 | gulp.task('dev', function(cb) { 542 | runSequence(['clean', 'watch:set'], ['copy', 'img-rev', 'compass', 'webpack'], 'watch', 'liveproxy', cb); 543 | }); 544 | 545 | gulp.task('dist', function(cb) { 546 | runSequence( 547 | 'clean', ['copy', 'img-rev', 'compass', 'webpack', 'uglify', 'minifyCss'], 548 | 'htmlrefs', 549 | customMinify, 550 | customJBFlow, 551 | cb); 552 | }); 553 | 554 | gulp.task('default', ['dev']); 555 | --------------------------------------------------------------------------------