合并develop 分支代码
Showing
24 changed files
with
632 additions
and
184 deletions
@@ -12,13 +12,25 @@ if (config.useOneapm) { | @@ -12,13 +12,25 @@ if (config.useOneapm) { | ||
12 | require('oneapm'); | 12 | require('oneapm'); |
13 | } | 13 | } |
14 | 14 | ||
15 | -let express = require('express'), | ||
16 | - path = require('path'), | ||
17 | - bodyParser = require('body-parser'), | ||
18 | - cookieParser = require('cookie-parser'), | ||
19 | - favicon = require('serve-favicon'); | 15 | +const express = require('express'); |
16 | +const path = require('path'); | ||
17 | +const bodyParser = require('body-parser'); | ||
18 | +const cookieParser = require('cookie-parser'); | ||
19 | +const favicon = require('serve-favicon'); | ||
20 | +const session = require('express-session'); | ||
21 | +const memcached = require('connect-memcached'); | ||
22 | +const pkg = require('./package.json'); | ||
20 | 23 | ||
21 | -let app = express(); | 24 | +const app = express(); |
25 | +const MemcachedStore = memcached(session); | ||
26 | + | ||
27 | + | ||
28 | +// 向模板注入变量 | ||
29 | +app.locals.devEnv = app.get('env') === 'development'; | ||
30 | +app.locals.version = pkg.version; | ||
31 | + | ||
32 | +// 指定libray目录 | ||
33 | +global.library = path.resolve('./library'); | ||
22 | 34 | ||
23 | app.set('view engine', '.hbs'); | 35 | app.set('view engine', '.hbs'); |
24 | 36 | ||
@@ -27,11 +39,22 @@ app.use(express.static(path.join(__dirname, 'public'))); | @@ -27,11 +39,22 @@ app.use(express.static(path.join(__dirname, 'public'))); | ||
27 | app.use(bodyParser.json()); | 39 | app.use(bodyParser.json()); |
28 | app.use(bodyParser.urlencoded({extended: false})); | 40 | app.use(bodyParser.urlencoded({extended: false})); |
29 | app.use(cookieParser()); | 41 | app.use(cookieParser()); |
42 | +app.use(session({ | ||
43 | + secret: '3e5fec7deca0b8305cefe2ad9d90ff5e', | ||
44 | + name: 'PHPSESSID', | ||
45 | + prefix: 'yohobuy', | ||
46 | + proxy: true, | ||
47 | + resave: true, | ||
48 | + saveUninitialized: true, | ||
49 | + store: new MemcachedStore({ | ||
50 | + hosts: config.memcache.session | ||
51 | + }) | ||
52 | +})); | ||
30 | 53 | ||
31 | // dispatcher | 54 | // dispatcher |
32 | require('./dispatch')(app); | 55 | require('./dispatch')(app); |
33 | 56 | ||
34 | // listener | 57 | // listener |
35 | -app.listen(6002, function() { | 58 | +app.listen(config.port, function() { |
36 | console.log('yohobuy start'); | 59 | console.log('yohobuy start'); |
37 | }); | 60 | }); |
apps/activity/controllers/special.js
0 → 100644
apps/activity/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app index | ||
3 | + * @author: bikai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/16 | ||
5 | + */ | ||
6 | + | ||
7 | +var express = require('express'), | ||
8 | + path = require('path'), | ||
9 | + hbs = require('express-handlebars'); | ||
10 | + | ||
11 | +var app = express(); | ||
12 | + | ||
13 | +// set view engin | ||
14 | +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | ||
15 | + | ||
16 | +app.set('views', path.join(__dirname, 'views/action')); | ||
17 | +app.engine('.hbs', hbs({ | ||
18 | + extname: '.hbs', | ||
19 | + defaultLayout: 'layout', | ||
20 | + layoutsDir: doraemon, | ||
21 | + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
22 | + helpers: 'helpers' | ||
23 | +})); | ||
24 | + | ||
25 | +// router | ||
26 | +app.use(require('./router')); | ||
27 | + | ||
28 | +module.exports = app; |
apps/activity/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app index | ||
3 | + * @author: bikai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/16 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const express = require('express'); | ||
10 | +const router = express.Router(); // eslint-disable-line | ||
11 | +const cRoot = './controllers'; | ||
12 | + | ||
13 | +const specialController = require(`${cRoot}/special`); | ||
14 | + | ||
15 | +// 专题活动 | ||
16 | +router.get(/^\/special\/(\d+)_(.*)\.html$/, specialController.special); | ||
17 | + | ||
18 | +module.exports = router; |
apps/activity/views/action/index.hbs
0 → 100644
apps/channel/controllers/index.js
0 → 100644
1 | +/** | ||
2 | + * girls controller | ||
3 | + * @author: 赵彪<bill.zhao@yoho.cn> | ||
4 | + * @date: 2016/05/16 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const headerModel = require('../../../doraemon/models/header'); | ||
10 | + | ||
11 | +// const channelModel = require('../models/index'); | ||
12 | + | ||
13 | +exports.boysIndex = (req, res) => { | ||
14 | + headerModel.requestHeaderData() | ||
15 | + .then(response => { | ||
16 | + let data = headerModel.setHeaderData(response.data, 'boys'); | ||
17 | + | ||
18 | + data.module = 'index'; | ||
19 | + data.page = 'index'; | ||
20 | + data.footerTop = true; | ||
21 | + | ||
22 | + res.render('boys', data); | ||
23 | + }) | ||
24 | + .catch(() => { | ||
25 | + res.render('error', {devEnv: true, pageErr: true}); | ||
26 | + }); | ||
27 | +}; | ||
28 | + | ||
29 | +exports.girlsIndex = (req, res) => { | ||
30 | + headerModel.requestHeaderData() | ||
31 | + .then(response => { | ||
32 | + let data = headerModel.setHeaderData(response.data, 'girls'); | ||
33 | + | ||
34 | + data.module = 'index'; | ||
35 | + data.page = 'index'; | ||
36 | + data.footerTop = true; | ||
37 | + | ||
38 | + res.render('girls', data); | ||
39 | + }) | ||
40 | + .catch(() => { | ||
41 | + res.render('error', {devEnv: true, pageErr: true}); | ||
42 | + }); | ||
43 | + | ||
44 | +}; |
apps/channel/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app girls | ||
3 | + * @author: biao<bill.zhao@yoho.cn> | ||
4 | + * @date: 2016/05/16 | ||
5 | + */ | ||
6 | + | ||
7 | +var express = require('express'), | ||
8 | + path = require('path'), | ||
9 | + hbs = require('express-handlebars'); | ||
10 | + | ||
11 | +var app = express(); | ||
12 | + | ||
13 | +// set view engin | ||
14 | +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root | ||
15 | + | ||
16 | +app.on('mount', function(parent) { | ||
17 | + delete parent.locals.settings; // 不继承父 App 的设置 | ||
18 | + Object.assign(app.locals, parent.locals); | ||
19 | +}); | ||
20 | + | ||
21 | +app.set('views', path.join(__dirname, 'views/action')); | ||
22 | +app.engine('.hbs', hbs({ | ||
23 | + extname: '.hbs', | ||
24 | + defaultLayout: 'layout', | ||
25 | + layoutsDir: doraemon, | ||
26 | + partialsDir: ['./views/partial', `${doraemon}/partial`], | ||
27 | + helpers: 'helpers' | ||
28 | +})); | ||
29 | + | ||
30 | +// router | ||
31 | +app.use(require('./router')); | ||
32 | + | ||
33 | +module.exports = app; |
apps/channel/models/index.js
0 → 100644
1 | +/** | ||
2 | + * girls model | ||
3 | + * @author: 赵彪<bill.zhao@yoho.cn> | ||
4 | + * @date: 2016/05/17 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | + | ||
8 | +// const _ = require('lodash'); | ||
9 | + | ||
10 | +const ServiceAPI = require(`${global.library}/api`).ServiceAPI; | ||
11 | +const sign = require(`${global.library}/sign`); | ||
12 | + | ||
13 | +const serviceApi = new ServiceAPI(); | ||
14 | + | ||
15 | +/** | ||
16 | + * 获取公共配置 | ||
17 | + * @param undefined | ||
18 | + * @return {Object} 配置对象 | ||
19 | + */ | ||
20 | +// const commonConfig = () => ({ | ||
21 | +// title: 'girls' | ||
22 | +// }); | ||
23 | + | ||
24 | +exports.getContent = () => { | ||
25 | + let data = sign.apiSign({ | ||
26 | + | ||
27 | + /* eslint-disable */ | ||
28 | + client_type: 'web' | ||
29 | + /* eslint-enable */ | ||
30 | + }); | ||
31 | + | ||
32 | + serviceApi.get('/operations/api/v5/resource/home', data).then(response => { | ||
33 | + console.log(response); | ||
34 | + }); | ||
35 | +}; |
apps/channel/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app girls | ||
3 | + * @author: biao<bill.zhao@yoho.cn> | ||
4 | + * @date: 2016/05/16 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const router = require('express').Router(); // eslint-disable-line | ||
10 | +const cRoot = './controllers'; | ||
11 | + | ||
12 | +// Your controller here | ||
13 | +const channelController = require(`${cRoot}/index`); | ||
14 | + | ||
15 | +router.get('/boys', channelController.boysIndex); | ||
16 | + | ||
17 | +module.exports = router; |
apps/channel/views/action/boys.hbs
0 → 100644
1 | +this is boys |
apps/channel/views/action/girls.hbs
0 → 100644
1 | +this is girls |
@@ -9,19 +9,17 @@ | @@ -9,19 +9,17 @@ | ||
9 | const headerModel = require('../../../doraemon/models/header'); | 9 | const headerModel = require('../../../doraemon/models/header'); |
10 | 10 | ||
11 | exports.index = (req, res) => { | 11 | exports.index = (req, res) => { |
12 | - headerModel.getHeaderData() | ||
13 | - .then(function(modelRes) { | ||
14 | - let response = JSON.parse(modelRes); | ||
15 | - let data = headerModel.getAllHeaderData(response.data, 'boy'); | 12 | + headerModel.requestHeaderData() |
13 | + .then(response => { | ||
14 | + let data = headerModel.setHeaderData(response.data, 'boys'); | ||
16 | 15 | ||
17 | - data.headerData.navbars[0].active = true; | ||
18 | data.module = 'index'; | 16 | data.module = 'index'; |
19 | data.page = 'index'; | 17 | data.page = 'index'; |
20 | data.footerTop = true; | 18 | data.footerTop = true; |
21 | 19 | ||
22 | res.render('index', data); | 20 | res.render('index', data); |
23 | }) | 21 | }) |
24 | - .catch(function() { | 22 | + .catch(() => { |
25 | res.render('index', {devEnv: true, pageErr: true}); | 23 | res.render('index', {devEnv: true, pageErr: true}); |
26 | }); | 24 | }); |
27 | }; | 25 | }; |
@@ -10,12 +10,20 @@ const isProduction = process.env.NODE_ENV === 'production'; | @@ -10,12 +10,20 @@ const isProduction = process.env.NODE_ENV === 'production'; | ||
10 | const isTest = process.env.NODE_ENV === 'test'; | 10 | const isTest = process.env.NODE_ENV === 'test'; |
11 | 11 | ||
12 | module.exports = { | 12 | module.exports = { |
13 | + port: 6002, | ||
13 | domains: { | 14 | domains: { |
14 | api: 'http://192.168.102.205:8080/gateway', | 15 | api: 'http://192.168.102.205:8080/gateway', |
15 | service: 'http://testservice.yoho.cn:28077', | 16 | service: 'http://testservice.yoho.cn:28077', |
16 | search: 'http://192.168.10.64:8080/yohosearch/' | 17 | search: 'http://192.168.10.64:8080/yohosearch/' |
17 | }, | 18 | }, |
18 | useOneapm: false, | 19 | useOneapm: false, |
20 | + useCache: true, | ||
21 | + memcache: { | ||
22 | + master: ['192.168.102.168:12580'], | ||
23 | + slave: ['192.168.102.168:12580'], | ||
24 | + session: ['192.168.102.168:12580'], | ||
25 | + timeout: 5000 | ||
26 | + }, | ||
19 | loggers: { | 27 | loggers: { |
20 | infoFile: { | 28 | infoFile: { |
21 | name: 'info', | 29 | name: 'info', |
@@ -8,7 +8,13 @@ module.exports = app => { | @@ -8,7 +8,13 @@ module.exports = app => { | ||
8 | 8 | ||
9 | // 公共服务 | 9 | // 公共服务 |
10 | 10 | ||
11 | + // 专题活动等活动页面 | ||
12 | + app.use(require('./apps/activity')); | ||
13 | + | ||
11 | // 业务模块 | 14 | // 业务模块 |
12 | app.use('/', require('./apps/index')); | 15 | app.use('/', require('./apps/index')); |
13 | app.use('/product', require('./apps/product')); | 16 | app.use('/product', require('./apps/product')); |
17 | + | ||
18 | + // 频道页 | ||
19 | + app.use('/', require('./apps/channel')); | ||
14 | }; | 20 | }; |
@@ -7,10 +7,9 @@ | @@ -7,10 +7,9 @@ | ||
7 | 'use strict'; | 7 | 'use strict'; |
8 | 8 | ||
9 | const _ = require('lodash'); | 9 | const _ = require('lodash'); |
10 | -const lRoot = '../../library/'; | ||
11 | 10 | ||
12 | -const ServiceAPI = require(`${lRoot}/api`).ServiceAPI; | ||
13 | -const sign = require(`${lRoot}/sign`); | 11 | +const ServiceAPI = require(`${global.library}/api`).ServiceAPI; |
12 | +const sign = require(`${global.library}/sign`); | ||
14 | 13 | ||
15 | const serviceApi = new ServiceAPI(); | 14 | const serviceApi = new ServiceAPI(); |
16 | 15 | ||
@@ -20,11 +19,22 @@ const serviceApi = new ServiceAPI(); | @@ -20,11 +19,22 @@ const serviceApi = new ServiceAPI(); | ||
20 | * @return {Object} 配置对象 | 19 | * @return {Object} 配置对象 |
21 | */ | 20 | */ |
22 | const commonConfig = () => ({ | 21 | const commonConfig = () => ({ |
23 | - title: 'home', | ||
24 | - devEnv: true, | ||
25 | - version: '0.0.1' | 22 | + title: 'home' |
26 | }); | 23 | }); |
27 | 24 | ||
25 | +const getChannelIndex = (type) => { | ||
26 | + const channelMap = { | ||
27 | + boys: 0, | ||
28 | + girls: 1, | ||
29 | + kids: 2, | ||
30 | + lifestyle: 3 | ||
31 | + }; | ||
32 | + | ||
33 | + const index = channelMap[type]; | ||
34 | + | ||
35 | + return _.isNil(index) ? 0 : index; | ||
36 | +}; | ||
37 | + | ||
28 | /** | 38 | /** |
29 | * 获取菜单 | 39 | * 获取菜单 |
30 | * @param undefined | 40 | * @param undefined |
@@ -138,26 +148,7 @@ const getThirdNav = (data) => { | @@ -138,26 +148,7 @@ const getThirdNav = (data) => { | ||
138 | const getSubNav = (data, type) => { | 148 | const getSubNav = (data, type) => { |
139 | let subNav = []; | 149 | let subNav = []; |
140 | 150 | ||
141 | - let index; | ||
142 | - | ||
143 | - switch (type) { | ||
144 | - case 'boy': | ||
145 | - index = 0; | ||
146 | - break; | ||
147 | - case 'girl': | ||
148 | - index = 1; | ||
149 | - break; | ||
150 | - case 'kids': | ||
151 | - index = 2; | ||
152 | - break; | ||
153 | - case 'lifestyle': | ||
154 | - index = 3; | ||
155 | - break; | ||
156 | - default: | ||
157 | - index = 0; | ||
158 | - } | ||
159 | - | ||
160 | - _.forEach(data[index].sub, function(item) { | 151 | + _.forEach(data[getChannelIndex(type)].sub, function(item) { |
161 | let obj = {}; | 152 | let obj = {}; |
162 | 153 | ||
163 | obj.link = item.sort_url; | 154 | obj.link = item.sort_url; |
@@ -177,23 +168,28 @@ const getSubNav = (data, type) => { | @@ -177,23 +168,28 @@ const getSubNav = (data, type) => { | ||
177 | }; | 168 | }; |
178 | 169 | ||
179 | 170 | ||
171 | + | ||
172 | + | ||
180 | /** | 173 | /** |
181 | * 处理接口返回的数据 | 174 | * 处理接口返回的数据 |
182 | * @param {object} 接口返回的对象 | 175 | * @param {object} 接口返回的对象 |
176 | + * @param {String} 指定页面类型为boys,girls,kids,lifestyle | ||
183 | * @return {object} 头部数据 | 177 | * @return {object} 头部数据 |
184 | */ | 178 | */ |
185 | -exports.getAllHeaderData = function(resData, type) { | 179 | +exports.setHeaderData = (resData, type) => { |
186 | let config = commonConfig(); | 180 | let config = commonConfig(); |
187 | let data = { | 181 | let data = { |
188 | headerData: { | 182 | headerData: { |
189 | header: true, | 183 | header: true, |
190 | - type: type, | 184 | + headType: type, |
191 | yohoGroup: getMenuData(), | 185 | yohoGroup: getMenuData(), |
192 | navbars: getNavBar(resData), | 186 | navbars: getNavBar(resData), |
193 | subNav: getSubNav(resData, type) | 187 | subNav: getSubNav(resData, type) |
194 | } | 188 | } |
195 | }; | 189 | }; |
196 | 190 | ||
191 | + data.headerData.navbars[getChannelIndex(type)].active = true; | ||
192 | + | ||
197 | return _.merge(config, data); | 193 | return _.merge(config, data); |
198 | }; | 194 | }; |
199 | 195 | ||
@@ -202,15 +198,13 @@ exports.getAllHeaderData = function(resData, type) { | @@ -202,15 +198,13 @@ exports.getAllHeaderData = function(resData, type) { | ||
202 | * @param undefined | 198 | * @param undefined |
203 | * @return {promise} | 199 | * @return {promise} |
204 | */ | 200 | */ |
205 | -exports.getHeaderData = function() { | 201 | +exports.requestHeaderData = () => { |
206 | let data = sign.apiSign({ | 202 | let data = sign.apiSign({ |
207 | 203 | ||
208 | /* eslint-disable */ | 204 | /* eslint-disable */ |
209 | - client_type: 'web', | 205 | + client_type: 'web' |
210 | /* eslint-enable */ | 206 | /* eslint-enable */ |
211 | }); | 207 | }); |
212 | 208 | ||
213 | - return serviceApi.get('/operations/api/v6/category/getCategory', data); | 209 | + return serviceApi.get('/operations/api/v6/category/getCategory', data, true); |
214 | }; | 210 | }; |
215 | - | ||
216 | - |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | <link rel="dns-prefetch" href="//img12.static.yhbimg.com"> | 15 | <link rel="dns-prefetch" href="//img12.static.yhbimg.com"> |
16 | <link rel="dns-prefetch" href="//img13.static.yhbimg.com"> | 16 | <link rel="dns-prefetch" href="//img13.static.yhbimg.com"> |
17 | {{#if devEnv}} | 17 | {{#if devEnv}} |
18 | - <link rel="stylesheet" href="//localhost:5000/css/index.css"> | 18 | + <link rel="stylesheet" href="//localhost:5002/css/index.css"> |
19 | {{^}} | 19 | {{^}} |
20 | <link rel="stylesheet" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css"> | 20 | <link rel="stylesheet" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css"> |
21 | {{/if}} | 21 | {{/if}} |
@@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
29 | {{/if}} | 29 | {{/if}} |
30 | {{> footer}} | 30 | {{> footer}} |
31 | {{#if devEnv}} | 31 | {{#if devEnv}} |
32 | - <script src="//localhost:5000/{{module}}.{{page}}.js"></script> | 32 | + <script src="//localhost:5002/{{module}}.{{page}}.js"></script> |
33 | {{^}} | 33 | {{^}} |
34 | <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script> | 34 | <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script> |
35 | {{/if}} | 35 | {{/if}} |
1 | {{# headerData}} | 1 | {{# headerData}} |
2 | - <div class="yoho-header {{headtype}}"> | 2 | + <div class="yoho-header {{headType}}"> |
3 | <div class="tool-wrapper clearfix"> | 3 | <div class="tool-wrapper clearfix"> |
4 | <div class="center-content"> | 4 | <div class="center-content"> |
5 | <div class="yoho-group-map left"> | 5 | <div class="yoho-group-map left"> |
@@ -7,12 +7,16 @@ | @@ -7,12 +7,16 @@ | ||
7 | 'use strict'; | 7 | 'use strict'; |
8 | 8 | ||
9 | const rp = require('request-promise'); | 9 | const rp = require('request-promise'); |
10 | +const qs = require('querystring'); | ||
11 | +const md5 = require('md5'); | ||
10 | const _ = require('lodash'); | 12 | const _ = require('lodash'); |
11 | const log = require('./logger'); | 13 | const log = require('./logger'); |
12 | -const api = require('../config/common').domains.api; | ||
13 | -const serviceApi = require('../config/common').domains.service; | ||
14 | -const searchApi = require('../config/common').domains.search; | 14 | +const cache = require('./cache'); |
15 | const Timer = require('./timer'); | 15 | const Timer = require('./timer'); |
16 | +const config = require('../config/common'); | ||
17 | +const api = config.domains.api; | ||
18 | +const serviceApi = config.domains.service; | ||
19 | +const searchApi = config.domains.search; | ||
16 | 20 | ||
17 | 21 | ||
18 | let ApiUrl; | 22 | let ApiUrl; |
@@ -24,54 +28,107 @@ class API { | @@ -24,54 +28,107 @@ class API { | ||
24 | } | 28 | } |
25 | 29 | ||
26 | /** | 30 | /** |
27 | - * get | ||
28 | - * @param url String | ||
29 | - * @param data Obejct | 31 | + * 获取请求 ID |
30 | */ | 32 | */ |
31 | - get(url, data) { | ||
32 | - | ||
33 | - let options = { | ||
34 | - url: `${ApiUrl}${url}`, | ||
35 | - qs: data | ||
36 | - }; | 33 | + _getReqId(options) { |
34 | + return md5(`${options.url}?${qs.stringify(options.qs || options.form)}`); | ||
35 | + } | ||
37 | 36 | ||
37 | + /** | ||
38 | + * 调用接口 | ||
39 | + */ | ||
40 | + _requestFromAPI(options, cacheOption, reqId) { | ||
38 | let timer = new Timer(); | 41 | let timer = new Timer(); |
39 | 42 | ||
40 | timer.put('getApi');// 统计时间开始 | 43 | timer.put('getApi');// 统计时间开始 |
41 | 44 | ||
42 | - let ret = rp(options); | ||
43 | - | ||
44 | - ret.then((body)=>{ | ||
45 | - let duration = timer.put('getApi');// 接口返回 | ||
46 | - | ||
47 | - log.info('API GET: %s, parms: %j , durationMs: %d ms , body: %s', options.url, options.qs, duration, body); | 45 | + log.info(`get api: ${options.url}?${qs.stringify(options.qs)}`); |
46 | + return rp(options).then((result) => { | ||
47 | + let duration = timer.put('getApi');// 统计时间结束 | ||
48 | + | ||
49 | + log.info(`get api success: use: ${duration}ms`); | ||
50 | + if (config.useCache && cacheOption) { | ||
51 | + reqId = reqId || this._getReqId(options); | ||
52 | + | ||
53 | + // 数据校验无误,写缓存, 否则返回 Slave 缓存服务器的数据 | ||
54 | + if (result && result.code) { | ||
55 | + let cacheTime = _.isNumber(cacheOption) ? cacheOption : 60; | ||
56 | + | ||
57 | + cache.set(`apiCache:${reqId}`, result, cacheTime); | ||
58 | + cache.setSlave(`apiCache:${reqId}`, result, cacheTime); | ||
59 | + } else { | ||
60 | + return this._requestFromCache(options, true); | ||
61 | + } | ||
62 | + } | ||
63 | + return result; | ||
48 | }).catch((error)=>{ | 64 | }).catch((error)=>{ |
49 | - let duration = timer.put('getApi');// 接口返回 | 65 | + let duration = timer.put('getApi');// 统计时间结束 |
50 | 66 | ||
51 | - log.error('API GET: %s, parms: %j , durationMs: %d ms error: %s , statusCode: %d', | ||
52 | - options.url, options.qs, duration, error.message, error.statusCode); | ||
53 | - }); | 67 | + log.error(`get api fail: use: ${duration}ms, statusCode: ${error.statusCode}, error: ${error.message}`); |
54 | 68 | ||
55 | - return ret; | 69 | + // 使用缓存的时候,读取二级缓存 |
70 | + if (config.useCache) { | ||
71 | + return this._requestFromCache(options, true); | ||
72 | + } | ||
73 | + return Promise.reject({ | ||
74 | + error: '接口调用失败' | ||
75 | + }); | ||
76 | + }); | ||
56 | } | 77 | } |
57 | 78 | ||
58 | /** | 79 | /** |
59 | - * multi get | ||
60 | - * @params: urls => Array[Object[url[string], data[object]]] | 80 | + * 读取缓存 |
81 | + * @param {[object]} options | ||
82 | + * @param {[boolean]} slave true: 读取二级缓存 | ||
83 | + * @return {[type]} | ||
61 | */ | 84 | */ |
62 | - multiGet(urls) { | ||
63 | - var rps = []; | ||
64 | - | ||
65 | - _.forEach(urls, function(el) { | ||
66 | - rps.push(rp({ | ||
67 | - url: `${ApiUrl}${el.url}`, | ||
68 | - qs: el.data | ||
69 | - })); | 85 | + _requestFromCache(options, slave) { |
86 | + let reqId = this._getReqId(options); | ||
87 | + let getCache = slave ? cache.getFromSlave : cache.get; | ||
88 | + | ||
89 | + log.info(`get cache: ${reqId}, url: ${options.url}?${qs.stringify(options.qs)}`); | ||
90 | + return getCache(`apiCache:${reqId}`).then((result) => { | ||
91 | + if (!_.isNil(result)) { | ||
92 | + try { | ||
93 | + result = JSON.parse(result); | ||
94 | + } finally { | ||
95 | + log.info(slave ? 'get slave cache success' : 'get master cache success'); | ||
96 | + return result; | ||
97 | + } | ||
98 | + } | ||
99 | + | ||
100 | + if (!slave) { | ||
101 | + return this._requestFromAPI(options, true, reqId); | ||
102 | + } | ||
103 | + }).catch(() => { | ||
104 | + log.error(slave ? 'get slave cache fail' : 'get master cache fail'); | ||
105 | + if (!slave) { | ||
106 | + return this._requestFromAPI(options, true, reqId); | ||
107 | + } | ||
70 | }); | 108 | }); |
109 | + } | ||
71 | 110 | ||
72 | - return Promise.all(rps).then((d) => { | ||
73 | - return d; | ||
74 | - }); | 111 | + /** |
112 | + * 使用 get 请求获取接口 | ||
113 | + * @param {[string]} url | ||
114 | + * @param {[object]} data | ||
115 | + * @param {[bool or number]} cacheOption 使用数字时,数字表示缓存时间 | ||
116 | + * @return {[type]} | ||
117 | + */ | ||
118 | + get(url, data, cacheOption) { | ||
119 | + let options = { | ||
120 | + url: `${ApiUrl}${url}`, | ||
121 | + qs: data, | ||
122 | + json: true, | ||
123 | + timeout: 3000 | ||
124 | + }; | ||
125 | + | ||
126 | + // 从缓存获取数据 | ||
127 | + if (config.useCache && cacheOption) { | ||
128 | + return this._requestFromCache(options); | ||
129 | + } | ||
130 | + | ||
131 | + return this._requestFromAPI(options, cacheOption); | ||
75 | } | 132 | } |
76 | 133 | ||
77 | /** | 134 | /** |
@@ -80,11 +137,22 @@ class API { | @@ -80,11 +137,22 @@ class API { | ||
80 | * @param data Obejct | 137 | * @param data Obejct |
81 | */ | 138 | */ |
82 | post(url, data) { | 139 | post(url, data) { |
83 | - return rp({ | 140 | + let options = { |
84 | url: `${ApiUrl}${url}`, | 141 | url: `${ApiUrl}${url}`, |
142 | + form: data, | ||
85 | method: 'post', | 143 | method: 'post', |
86 | - form: data | ||
87 | - }); | 144 | + json: true, |
145 | + timeout: 3000 | ||
146 | + }; | ||
147 | + | ||
148 | + return this._requestFromAPI(options); | ||
149 | + } | ||
150 | + | ||
151 | + all(list) { | ||
152 | + if (_.isArray(list)) { | ||
153 | + return Promise.all(list); | ||
154 | + } | ||
155 | + throw Error('the parameters of api all method should be Array!'); | ||
88 | } | 156 | } |
89 | } | 157 | } |
90 | 158 |
library/cache.js
0 → 100644
1 | +/** | ||
2 | + * 缓存封装 | ||
3 | + * 前期使用 memcache, 写方法的时候考虑一下如何转换为 redis | ||
4 | + * @author bikai kai.bi@yoho.cn | ||
5 | + * @date 2016/05/16 | ||
6 | + */ | ||
7 | + | ||
8 | +'use strict'; | ||
9 | +const Promise = require('bluebird'); | ||
10 | +const Memcached = require('memcached'); | ||
11 | +const _ = require('lodash'); | ||
12 | +const log = require('./logger'); | ||
13 | +const config = require('../config/common'); | ||
14 | + | ||
15 | +let master = new Memcached(config.memcache.master, config.memcache); | ||
16 | +let slave = new Memcached(config.memcache.slave, config.memcache); | ||
17 | + | ||
18 | +master = Promise.promisifyAll(master); | ||
19 | +slave = Promise.promisifyAll(slave); | ||
20 | + | ||
21 | +/** | ||
22 | + * 获取缓存 | ||
23 | + * @param {[string]} key 键 | ||
24 | + * @return {[type]} | ||
25 | + */ | ||
26 | +exports.get = (key) => { | ||
27 | + if (_.isString(key)) { | ||
28 | + return master.getAsync(key); | ||
29 | + } | ||
30 | + | ||
31 | + return Promise.resolve(); | ||
32 | +}; | ||
33 | + | ||
34 | +/** | ||
35 | + * 批量获取缓存 | ||
36 | + * @param {[array]} list 字符串数组 | ||
37 | + * @return {[type]} | ||
38 | + */ | ||
39 | +exports.getMulti = (list) => { | ||
40 | + if (_.isArray(list)) { | ||
41 | + return master.getMultiAsync(list); | ||
42 | + } | ||
43 | + return Promise.resolve(); | ||
44 | +}; | ||
45 | + | ||
46 | +/** | ||
47 | + * 获取缓存(从 Slave 服务器) | ||
48 | + * @param {[string]} key 键 | ||
49 | + * @return {[type]} | ||
50 | + */ | ||
51 | +exports.getFromSlave = (key) => { | ||
52 | + if (_.isString(key)) { | ||
53 | + return slave.getAsync(key); | ||
54 | + } | ||
55 | + return Promise.resolve(); | ||
56 | +}; | ||
57 | + | ||
58 | +/** | ||
59 | + * 批量获取缓存(从 Slave 服务器) | ||
60 | + * @param {[array]} list 字符串数组 | ||
61 | + * @return {[type]} | ||
62 | + */ | ||
63 | +exports.getMultiFromSlave = (list) => { | ||
64 | + if (_.isArray(list)) { | ||
65 | + return slave.getMultiAsync(list); | ||
66 | + } | ||
67 | + return Promise.resolve(); | ||
68 | +}; | ||
69 | + | ||
70 | +/** | ||
71 | + * 写缓存 | ||
72 | + * @param {[type]} key 键 | ||
73 | + * @param {[type]} value 值 | ||
74 | + * @param {[type]} lifetime 生命周期 | ||
75 | + * @return {[type]} | ||
76 | + */ | ||
77 | +exports.set = (key, value, lifetime) => { | ||
78 | + lifetime = lifetime || 86400; | ||
79 | + | ||
80 | + log.info(`write cache: ${key}`); | ||
81 | + if (_.isObject(value)) { | ||
82 | + value = JSON.stringify(value); | ||
83 | + } | ||
84 | + | ||
85 | + if (_.isString(key)) { | ||
86 | + return master.setAsync(key, value, lifetime); | ||
87 | + } | ||
88 | + return Promise.resolve(); | ||
89 | +}; | ||
90 | + | ||
91 | +/** | ||
92 | + * 写缓存(到 Slave 服务器) | ||
93 | + * @param {[type]} key 键 | ||
94 | + * @param {[type]} value 值 | ||
95 | + * @param {[type]} lifetime 生命周期 | ||
96 | + * @return {[type]} | ||
97 | + */ | ||
98 | +exports.setSlave = (key, value, lifetime) => { | ||
99 | + lifetime = lifetime || 86400; | ||
100 | + | ||
101 | + if (_.isObject(value)) { | ||
102 | + value = JSON.stringify(value); | ||
103 | + } | ||
104 | + | ||
105 | + if (_.isString(key)) { | ||
106 | + return slave.setAsync(key, value, lifetime); | ||
107 | + } | ||
108 | + return Promise.resolve(); | ||
109 | +}; | ||
110 | + | ||
111 | +/** | ||
112 | + * 删除缓存 | ||
113 | + * @param {[string]} key 键 | ||
114 | + * @return {[type]} | ||
115 | + */ | ||
116 | +exports.del = (key) => { | ||
117 | + if (_.isString(key)) { | ||
118 | + return master.delAsync(key); | ||
119 | + } | ||
120 | + return Promise.resolve(); | ||
121 | +}; |
library/camel-case.js
0 → 100644
1 | +/** | ||
2 | + * 对象键名驼峰化 | ||
3 | + * @author: Bi Kai<kai.bi@yoho.cn> | ||
4 | + * @date: 2016/05/09 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | +const _ = require('lodash'); | ||
8 | + | ||
9 | +let camelCase, | ||
10 | + camelCaseObject, | ||
11 | + camelCaseArray; | ||
12 | + | ||
13 | +camelCaseObject = (obj) => { | ||
14 | + _.forEach(Object.keys(obj), (k) => { | ||
15 | + obj[k] = camelCase(obj[k]); | ||
16 | + obj[_.camelCase(k)] = obj[k]; | ||
17 | + }); | ||
18 | + return obj; | ||
19 | +}; | ||
20 | + | ||
21 | +camelCaseArray = (list) => { | ||
22 | + _.forEach(list, (k) => { | ||
23 | + k = camelCase(k); | ||
24 | + }); | ||
25 | + return list; | ||
26 | +}; | ||
27 | + | ||
28 | +camelCase = (data) => { | ||
29 | + if (_.isObject(data)) { | ||
30 | + data = camelCaseObject(data); | ||
31 | + } | ||
32 | + | ||
33 | + if (_.isArray(data)) { | ||
34 | + data = camelCaseArray(data); | ||
35 | + } | ||
36 | + | ||
37 | + return data; | ||
38 | +}; | ||
39 | + | ||
40 | +module.exports = camelCase; |
1 | -/* | ||
2 | - * @Author: Targaryen | ||
3 | - * @Date: 2016-05-10 10:11:34 | ||
4 | - * @Last Modified by: Targaryen | ||
5 | - * @Last Modified time: 2016-05-12 11:25:53 | 1 | +/** |
2 | + * Handlebars helpers | ||
3 | + * bikai kai.bi@yoho.cn | ||
4 | + * 2016-05-10 | ||
6 | */ | 5 | */ |
7 | -/* ----------------------------------------- | ||
8 | - * 实现 PHP 的 Helpers 函数 | ||
9 | - * ----------------------------------------- | ||
10 | - */ | ||
11 | - | ||
12 | 'use strict'; | 6 | 'use strict'; |
13 | - | ||
14 | -const SUB_DOMAIN = '.yohobuy.com'; | ||
15 | -const SITE_MAIN = 'http://www.yohobuy.com'; | 7 | +const querystring = require('querystring'); |
16 | const _ = require('lodash'); | 8 | const _ = require('lodash'); |
9 | +const config = require('../config/common'); | ||
17 | 10 | ||
18 | -class HELPERS { | ||
19 | - | ||
20 | - /** | ||
21 | - * 构建网站的URL | ||
22 | - * @param uri String | ||
23 | - * @param param Array | ||
24 | - * @param module String | ||
25 | - */ | ||
26 | - url(uri, param, module) { | ||
27 | - let url = ''; | ||
28 | - | ||
29 | - if (module === null) { | ||
30 | - module = 'index'; | ||
31 | - } | ||
32 | - switch (module) { | ||
33 | - case 'default': | ||
34 | - url = 'http://m.yohobuy.com'; | ||
35 | - break; | ||
36 | - case 'guang': | ||
37 | - url = 'http://guang' + SUB_DOMAIN; | ||
38 | - break; | ||
39 | - case 'list': | ||
40 | - url = 'http://list' + SUB_DOMAIN; | ||
41 | - break; | ||
42 | - case 'search': | ||
43 | - url = 'http://search' + SUB_DOMAIN; | ||
44 | - break; | ||
45 | - case 'index': | ||
46 | - url = SITE_MAIN; | ||
47 | - break; | ||
48 | - case '': | ||
49 | - break; | ||
50 | - case undefined: | ||
51 | - break; | ||
52 | - default: | ||
53 | - url = 'http://' + module + SUB_DOMAIN; | ||
54 | - break; | ||
55 | - } | 11 | +/** |
12 | + * 七牛图片路径处理 | ||
13 | + * @param {[tring]} url | ||
14 | + * @param {[tring]} width | ||
15 | + * @param {[tring]} height | ||
16 | + * @param {[tring]} mode | ||
17 | + * @return {[tring]} | ||
18 | + */ | ||
19 | +exports.image = (url, width, height, mode) => { | ||
20 | + mode = _.isNumber(mode) ? mode : 2; | ||
21 | + url = url || ''; | ||
22 | + return url.replace(/{width}/g, width).replace(/{height}/g, height).replace(/{mode}/g, mode); | ||
23 | +}; | ||
56 | 24 | ||
57 | - url += uri; | ||
58 | - if (param !== null && param !== undefined) { | ||
59 | - url += '?'; | ||
60 | - _.forEach(param, function(value, key) { | ||
61 | - url += (key + '=' + value + '&'); | ||
62 | - }); | ||
63 | - } | ||
64 | - if (url.substr(-1, 1) === '&') { | ||
65 | - return url.substr(0, url.length - 1); | ||
66 | - } else { | ||
67 | - return url; | ||
68 | - } | 25 | +/** |
26 | + * 站内地址格式化 | ||
27 | + * @param {[string]} uri 路径 | ||
28 | + * @param {[object]} qs 查询字符串 | ||
29 | + * @param {[string]} module 模块 | ||
30 | + * @return {[string]} | ||
31 | + */ | ||
32 | +exports.url = (uri, qs, module) => { | ||
33 | + const subDomain = '.m.yohobuy.com'; | ||
34 | + const subName = { | ||
35 | + default: config.siteUrl, | ||
36 | + guang: '//guang' + subDomain, | ||
37 | + list: '//list' + subDomain, | ||
38 | + search: '//search' + subDomain, | ||
39 | + huodong: '//huodong' + subDomain, | ||
40 | + activity: '//activity.yohobuy.com', | ||
41 | + index: config.siteUrl | ||
42 | + }; | ||
43 | + let url; | ||
69 | 44 | ||
45 | + module = module || 'default'; | ||
46 | + if (subName[module]) { | ||
47 | + url = subName[module]; | ||
48 | + } else { | ||
49 | + url = '//' + module + subDomain; // 规则没匹配到就把模块当作子域名 | ||
70 | } | 50 | } |
71 | 51 | ||
72 | - /** | ||
73 | - * 根据尺寸获得图片url | ||
74 | - * @param uri String | ||
75 | - * @param param Array | ||
76 | - * @param module String | ||
77 | - */ | ||
78 | - getImageUrl(url, width, height, mode) { | ||
79 | - if (mode === null) { | ||
80 | - mode = 2; | ||
81 | - } | ||
82 | - return url.replace(/{width}/g, width) | ||
83 | - .replace(/{height}/g, height) | ||
84 | - .replace(/{mode}/g, mode); | 52 | + url += uri; |
53 | + if (qs) { | ||
54 | + url += '?' + querystring.stringify(qs); | ||
85 | } | 55 | } |
86 | -} | ||
87 | 56 | ||
88 | -module.exports = HELPERS; | 57 | + return url; |
58 | +}; | ||
59 | + | ||
60 | + | ||
61 | +/** | ||
62 | + * 大写转小写处理 | ||
63 | + * @param {[string]} str 转换字符 | ||
64 | + */ | ||
65 | +exports.lowerCase = (str) => { | ||
66 | + str = str || ''; | ||
67 | + return str.toLowerCase(); | ||
68 | +}; | ||
69 | + | ||
70 | +/** | ||
71 | + * 小写转大写处理 | ||
72 | + * @param {[string]} str 转换字符 | ||
73 | + */ | ||
74 | +exports.upperCase = (str) => { | ||
75 | + str = str || ''; | ||
76 | + return str.toUpperCase(); | ||
77 | +}; |
@@ -5,7 +5,6 @@ | @@ -5,7 +5,6 @@ | ||
5 | */ | 5 | */ |
6 | 6 | ||
7 | 'use strict'; | 7 | 'use strict'; |
8 | - | ||
9 | const _ = require('lodash'); | 8 | const _ = require('lodash'); |
10 | const md5 = require('md5'); | 9 | const md5 = require('md5'); |
11 | 10 | ||
@@ -24,7 +23,7 @@ const privateKey = { | @@ -24,7 +23,7 @@ const privateKey = { | ||
24 | * @return {Object} 排序之后的参数对象 | 23 | * @return {Object} 排序之后的参数对象 |
25 | */ | 24 | */ |
26 | const packageSort = argument => { | 25 | const packageSort = argument => { |
27 | - var newObj = {}; | 26 | + let newObj = {}; |
28 | 27 | ||
29 | for (let k of Object.keys(argument).sort()) { | 28 | for (let k of Object.keys(argument).sort()) { |
30 | newObj[k] = argument[k]; | 29 | newObj[k] = argument[k]; |
@@ -39,7 +38,7 @@ const packageSort = argument => { | @@ -39,7 +38,7 @@ const packageSort = argument => { | ||
39 | * @return {string} 生成的签名字符串 | 38 | * @return {string} 生成的签名字符串 |
40 | */ | 39 | */ |
41 | const makeSign = argument => { | 40 | const makeSign = argument => { |
42 | - var qs = []; | 41 | + let qs = []; |
43 | 42 | ||
44 | _.forEach(argument, function(value, key) { | 43 | _.forEach(argument, function(value, key) { |
45 | qs.push(key + '=' + _.trim(value)); | 44 | qs.push(key + '=' + _.trim(value)); |
@@ -50,11 +49,10 @@ const makeSign = argument => { | @@ -50,11 +49,10 @@ const makeSign = argument => { | ||
50 | 49 | ||
51 | // 生成API签名,调用后端接口的时候有私钥校验 | 50 | // 生成API签名,调用后端接口的时候有私钥校验 |
52 | exports.apiSign = (params) => { | 51 | exports.apiSign = (params) => { |
53 | - | ||
54 | - var clientType = params.client_type || 'h5'; | 52 | + const clientType = params.client_type || 'web'; |
55 | 53 | ||
56 | /* eslint-disable */ | 54 | /* eslint-disable */ |
57 | - var sign = packageSort(Object.assign({ | 55 | + let sign = packageSort(Object.assign({ |
58 | client_type: clientType, | 56 | client_type: clientType, |
59 | private_key: privateKey[clientType], | 57 | private_key: privateKey[clientType], |
60 | app_version: '3.8.2', | 58 | app_version: '3.8.2', |
@@ -62,18 +60,18 @@ exports.apiSign = (params) => { | @@ -62,18 +60,18 @@ exports.apiSign = (params) => { | ||
62 | screen_size: '720x1280', | 60 | screen_size: '720x1280', |
63 | v: '7' | 61 | v: '7' |
64 | }, params)); | 62 | }, params)); |
65 | - | ||
66 | /* eslint-enable */ | 63 | /* eslint-enable */ |
67 | 64 | ||
68 | - return Object.assign(sign, { | ||
69 | - | 65 | + sign = Object.assign(sign, { |
70 | client_secret: makeSign(sign) // eslint-disable-line camelcase | 66 | client_secret: makeSign(sign) // eslint-disable-line camelcase |
71 | }); | 67 | }); |
68 | + delete sign.private_key; | ||
69 | + return sign; | ||
72 | }; | 70 | }; |
73 | 71 | ||
74 | // 检查签名,APP 访问 H5 页面的时候需要检查 | 72 | // 检查签名,APP 访问 H5 页面的时候需要检查 |
75 | exports.checkSign = (params) => { | 73 | exports.checkSign = (params) => { |
76 | - var clientSecret = params.client_secret, // eslint-disable-line camelcase | 74 | + let clientSecret = params.client_secret, // eslint-disable-line camelcase |
77 | sortedParams; | 75 | sortedParams; |
78 | 76 | ||
79 | // 忽略部分参数 | 77 | // 忽略部分参数 |
@@ -90,7 +88,7 @@ exports.checkSign = (params) => { | @@ -90,7 +88,7 @@ exports.checkSign = (params) => { | ||
90 | 88 | ||
91 | // 检查签名,APP 访问 H5 页面的时候需要检查, 有可能不同于上边的签名方式 | 89 | // 检查签名,APP 访问 H5 页面的时候需要检查, 有可能不同于上边的签名方式 |
92 | exports.webSign = (params) => { | 90 | exports.webSign = (params) => { |
93 | - var webPrivateKey = 'yohobuyapp'; | 91 | + const webPrivateKey = 'yohobuyapp'; |
94 | 92 | ||
95 | return params.key === md5(md5(webPrivateKey) + params.uid); | 93 | return params.key === md5(md5(webPrivateKey) + params.uid); |
96 | }; | 94 | }; |
@@ -18,13 +18,17 @@ | @@ -18,13 +18,17 @@ | ||
18 | }, | 18 | }, |
19 | "license": "MIT", | 19 | "license": "MIT", |
20 | "dependencies": { | 20 | "dependencies": { |
21 | + "bluebird": "^3.3.5", | ||
21 | "body-parser": "^1.15.0", | 22 | "body-parser": "^1.15.0", |
23 | + "connect-memcached": "^0.2.0", | ||
22 | "cookie-parser": "^1.4.1", | 24 | "cookie-parser": "^1.4.1", |
23 | "express": "^4.13.1", | 25 | "express": "^4.13.1", |
24 | "express-handlebars": "^3.0.0", | 26 | "express-handlebars": "^3.0.0", |
27 | + "express-session": "^1.13.0", | ||
25 | "influxdb-winston": "^1.0.1", | 28 | "influxdb-winston": "^1.0.1", |
26 | "lodash": "^4.12.0", | 29 | "lodash": "^4.12.0", |
27 | "md5": "^2.1.0", | 30 | "md5": "^2.1.0", |
31 | + "memcached": "^2.2.1", | ||
28 | "morgan": "^1.7.0", | 32 | "morgan": "^1.7.0", |
29 | "oneapm": "^1.2.20", | 33 | "oneapm": "^1.2.20", |
30 | "request-promise": "^3.0.0", | 34 | "request-promise": "^3.0.0", |
@@ -34,7 +38,7 @@ | @@ -34,7 +38,7 @@ | ||
34 | }, | 38 | }, |
35 | "devDependencies": { | 39 | "devDependencies": { |
36 | "autoprefixer": "^6.3.6", | 40 | "autoprefixer": "^6.3.6", |
37 | - "eslint": "^2.9.0", | 41 | + "eslint": "^2.10.2", |
38 | "eslint-config-yoho": "^1.0.1", | 42 | "eslint-config-yoho": "^1.0.1", |
39 | "gulp": "^3.9.1", | 43 | "gulp": "^3.9.1", |
40 | "gulp-cssnano": "^2.1.2", | 44 | "gulp-cssnano": "^2.1.2", |
@@ -55,14 +59,17 @@ | @@ -55,14 +59,17 @@ | ||
55 | "postcss-position": "^0.4.0", | 59 | "postcss-position": "^0.4.0", |
56 | "postcss-short": "^1.4.0", | 60 | "postcss-short": "^1.4.0", |
57 | "postcss-sprites": "^3.1.2", | 61 | "postcss-sprites": "^3.1.2", |
58 | - "postcss-use": "^2.0.2", | 62 | + "postcss-use": "^2.1.0", |
59 | "precss": "^1.4.0", | 63 | "precss": "^1.4.0", |
60 | "rewire": "^2.5.1", | 64 | "rewire": "^2.5.1", |
61 | "shelljs": "^0.7.0", | 65 | "shelljs": "^0.7.0", |
62 | "stylelint": "^6.3.3", | 66 | "stylelint": "^6.3.3", |
63 | - "stylelint-config-yoho": "^1.2.2", | 67 | + "stylelint-config-yoho": "^1.2.3", |
64 | "webpack": "^1.13.0", | 68 | "webpack": "^1.13.0", |
65 | "webpack-dev-server": "^1.14.1", | 69 | "webpack-dev-server": "^1.14.1", |
66 | - "webpack-stream": "^3.1.0" | 70 | + "webpack-stream": "^3.1.0", |
71 | + "yoho-handlebars": "^4.0.5", | ||
72 | + "yoho-jquery": "^1.9.1", | ||
73 | + "yoho-jquery-lazyload": "^1.9.7" | ||
67 | } | 74 | } |
68 | } | 75 | } |
@@ -167,16 +167,19 @@ gulp.task('webpack-dev-server', () => { | @@ -167,16 +167,19 @@ gulp.task('webpack-dev-server', () => { | ||
167 | 167 | ||
168 | new WebpackDevServer(webpack(devConfig), { | 168 | new WebpackDevServer(webpack(devConfig), { |
169 | contentBase: '.', | 169 | contentBase: '.', |
170 | - publicPath: '//localhost:5000', | 170 | + publicPath: '//localhost:5002/', |
171 | hot: true, | 171 | hot: true, |
172 | stats: { | 172 | stats: { |
173 | colors: true | 173 | colors: true |
174 | + }, | ||
175 | + headers: { | ||
176 | + 'Access-Control-Allow-Origin': '*' | ||
174 | } | 177 | } |
175 | - }).listen(5000, 'localhost', (err) => { | 178 | + }).listen(5002, 'localhost', (err) => { |
176 | if (err) { | 179 | if (err) { |
177 | throw new gutil.PluginError('webpack-dev-server', err); | 180 | throw new gutil.PluginError('webpack-dev-server', err); |
178 | } | 181 | } |
179 | - gutil.log('[webpack-serve]', 'http://localhost:5000/'); | 182 | + gutil.log('[webpack-serve]', 'http://localhost:5002/'); |
180 | }); | 183 | }); |
181 | }); | 184 | }); |
182 | 185 |
-
Please register or login to post a comment