Authored by 陈峰

vue ssr 架构ok

... ... @@ -5,5 +5,11 @@
"browsers": [">1%", "android >=4", "ios >=8"]
}
}]
]
],
"plugins": [
"transform-runtime",
"transform-vue-jsx",
"transform-object-rest-spread",
"syntax-dynamic-import"
]
}
... ...
... ... @@ -146,4 +146,5 @@ public/bundle/*
nbproject/*
.DS_Store
.devhost
.happypack/
\ No newline at end of file
.happypack/
bundle/
\ No newline at end of file
... ...
/**
* yohobuy app
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/4/25
*/
'use strict';
const config = require('./config/common');
// use one apm
if (config.useOneapm) {
require('oneapm');
}
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const favicon = require('serve-favicon');
const yohoLib = require('yoho-node-lib');
const session = require('express-session');
const memcached = require('connect-memcached');
const pkg = require('./package.json');
const devtools = require('./doraemon/middleware/devtools');
const _ = require('lodash');
const {createApp} = require('./create-app.js');
const uuid = require('uuid');
const app = express();
const MemcachedStore = memcached(session);
// 向模板注入变量
app.locals.devEnv = app.get('env') === 'development';
app.locals.proEnv = app.get('env') === 'production';
app.locals.version = pkg.version;
// 全局注册library
yohoLib.global(config);
// 指定 doraemon, utils 目录
global.utils = path.resolve('./utils');
global.doraemon = path.resolve('./doraemon');
const logger = global.yoho.logger;
if (app.locals.devEnv) {
app.use(devtools());
}
app.use(global.yoho.hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: path.join(__dirname, 'doraemon/views'),
partialsDir: path.join(__dirname, 'doraemon/views/partial'),
views: path.join(__dirname, 'doraemon/views'),
helpers: _.assign(global.yoho.helpers, require('./utils/helpers'))
}));
app.use(favicon(path.join(__dirname, '/public/favicon.ico')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(session({
proxy: true,
resave: false,
saveUninitialized: true,
unset: 'destroy',
secret: '82dd7e724f2c6870472c89dfa43cf48d',
name: 'yohoblk_session',
cookie: {
domain: 'yohoblk.com',
httpOnly: false
},
store: new MemcachedStore({
hosts: config.memcache.session,
prefix: 'yohoblk_session:'
})
}));
app.use((req, res, next) => {
req.user = {}; // 全局的用户数据
req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
if (!req.sessionID) {
req.sessionID = uuid.v4();
}
next();
});
// dispatcher
try {
const user = require('./doraemon/middleware/user');
const setYohoData = require('./doraemon/middleware/set-yoho-data');
const errorHanlder = require('./doraemon/middleware/error-handler');
const setPageInfo = require('./doraemon/middleware/set-pageinfo');
const layoutTools = require('./doraemon/middleware/layout-tools');
// YOHO 前置中间件
app.use(setYohoData());
app.use(user());
app.use(setPageInfo());
app.use(layoutTools());
require('./dispatch')(app);
app.all('*', errorHanlder.notFound()); // 404
// YOHO 后置中间件
app.use(errorHanlder.serverError());
} catch (err) {
logger.error(err);
}
// listener
app.listen(config.port, function() {
logger.info('yohobuy start');
});
createApp(app);
... ...
import {subscribe} from 'webpack-hot-middleware/client';
subscribe(event => {
if (event.action === 'reload') {
window.location.reload();
}
});
... ...
const webpack = require('webpack');
const path = require('path');
const MFS = require('memory-fs');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
let clientConfig = require('./webpack.client.conf.js');
let serverConfig = require('./webpack.server.conf.js');
let devMiddleware;
let hotMiddleware;
const _readFile = (fs, file) => {
try {
return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8');
} catch (e) {
console.error('file load failure!', e);
}
};
exports.readFile = (file) => {
return _readFile(devMiddleware.fileSystem, file);
};
exports.publish = (data) => {
return hotMiddleware.publish(data);
};
exports.devServer = (app, cb) => {
let resolve;
let realyPromise = new Promise(r => {
resolve = r;
});
let ready = (...args) => {
resolve();
cb(...args);
};
clientConfig.entry.app = ['./build/client-hot.js', clientConfig.entry.app];
clientConfig.output.filename = '[name].js';
clientConfig.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
);
const clientCompiler = webpack(clientConfig);
devMiddleware = webpackDevMiddleware(clientCompiler, {
publicPath: clientConfig.output.publicPath,
quiet: true,
headers: {
'Access-Control-Allow-Origin': '*'
}
});
app.use(devMiddleware);
let bundle, clientManifest;
clientCompiler.plugin('done', stats => {
stats = stats.toJson();
stats.errors.forEach(error => console.log(error));
stats.warnings.forEach(warning => console.log(warning));
if (stats.errors.length) {
return;
}
clientManifest = JSON.parse(_readFile(devMiddleware.fileSystem, 'vue-ssr-client-manifest.json'));
if (bundle) {
ready({bundle, options: {clientManifest}});
}
});
hotMiddleware = webpackHotMiddleware(clientCompiler, { heartbeat: 5000 });
app.use(hotMiddleware);
const serverCompiler = webpack(serverConfig);
let mfs = new MFS();
serverCompiler.outputFileSystem = mfs;
serverCompiler.watch({}, (err, stats) => {
if (err) {
throw err;
}
stats = stats.toJson();
if (stats.errors.length) {
return;
}
bundle = JSON.parse(_readFile(mfs, 'vue-ssr-server-bundle.json'));
if (clientManifest) {
ready({bundle, options: {clientManifest}});
}
});
return realyPromise;
};
... ...
const autoprefixer = require('autoprefixer');
module.exports = () => {
return [
autoprefixer()
];
};
... ...
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
const postcssConfig = require('./postcss.config.js');
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
output: {
filename: 'static/js/[name].[chunkhash].js',
path: path.resolve(__dirname, '../bundle'),
chunkFilename: 'static/js/[name].[chunkhash].js',
publicPath: '/'
},
devtool: isProd ? '#source-map' : '#cheap-module-source-map',
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
path.join(__dirname, '../src'),
path.join(__dirname, '../src/statics/scss'),
'node_modules'
]
},
module: {
rules: [
{
test: /\.js$/,
loader: ['babel-loader'],
exclude: /node_modules/
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader' // <- 这是vue-loader的依赖,所以如果使用npm3,则不需要显式安装
}),
},
postcss: {
plugins: postcssConfig(),
opetions: {
sourceMap: true
}
}
}
}, {
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
use: {
loader: 'postcss-loader',
options: {
plugins: postcssConfig()
}
},
fallback: 'vue-style-loader'
})
}, {
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/img/[name].[chunkhash].[ext]'
}
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/fonts/[name].[chunkhash].[ext]'
}
},
]
},
plugins: [
new ExtractTextPlugin({
filename: 'static/css/[name].[chunkhash].css'
}),
new FriendlyErrorsPlugin()
]
};
... ...
const webpack = require('webpack');
const merge = require('webpack-merge');
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
let baseConfig = require('./webpack.base.conf');
const webpackConfig = merge(baseConfig, {
entry: {
app: './src/entry-client.js'
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.VUE_ENV': '"client"'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module) {
return (
/node_modules/.test(module.context) &&
!/\.css$/.test(module.request)
);
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
}),
new VueSSRClientPlugin(),
]
});
if (process.env.NODE_ENV === 'production') {
webpackConfig.plugins.push(new UglifyJSPlugin({
parallel: true,
sourceMap: true
}));
webpackConfig.output.publicPath = '//cdn.yoho.cn/yohoblk-wap/';
}
module.exports = webpackConfig;
... ...
const webpack = require('webpack');
const merge = require('webpack-merge');
const nodeExternals = require('webpack-node-externals');
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
let baseConfig = require('./webpack.base.conf');
let webpackConfig = merge(baseConfig, {
entry: './src/entry-server.js',
target: 'node',
devtool: 'source-map',
output: {
libraryTarget: 'commonjs2',
},
externals: nodeExternals({
whitelist: /\.css$/
}),
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.VUE_ENV': '"server"'
}),
new VueSSRServerPlugin(),
]
});
module.exports = webpackConfig;
... ...
/**
* yohobuy app
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/4/25
*/
'use strict';
const config = require('./config/common');
// use one apm
if (config.useOneapm) {
require('oneapm');
}
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const favicon = require('serve-favicon');
const yohoLib = require('yoho-node-lib');
const session = require('express-session');
const memcached = require('connect-memcached');
const pkg = require('./package.json');
const devtools = require('./doraemon/middleware/devtools');
const _ = require('lodash');
const uuid = require('uuid');
const MemcachedStore = memcached(session);
exports.createApp = (app) => {
// 向模板注入变量
app.locals.devEnv = app.get('env') === 'development';
app.locals.proEnv = app.get('env') === 'production';
app.locals.version = pkg.version;
// 全局注册library
yohoLib.global(config);
// 指定 doraemon, utils 目录
global.utils = path.resolve('./utils');
global.doraemon = path.resolve('./doraemon');
const logger = global.yoho.logger;
if (app.locals.devEnv) {
app.use(devtools());
}
app.use(global.yoho.hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: path.join(__dirname, 'doraemon/views'),
partialsDir: path.join(__dirname, 'doraemon/views/partial'),
views: path.join(__dirname, 'doraemon/views'),
helpers: _.assign(global.yoho.helpers, require('./utils/helpers'))
}));
app.use(favicon(path.join(__dirname, '/public/favicon.ico')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(session({
proxy: true,
resave: false,
saveUninitialized: true,
unset: 'destroy',
secret: '82dd7e724f2c6870472c89dfa43cf48d',
name: 'yohoblk_session',
cookie: {
domain: 'yohoblk.com',
httpOnly: false
},
store: new MemcachedStore({
hosts: config.memcache.session,
prefix: 'yohoblk_session:'
})
}));
app.use((req, res, next) => {
req.user = {}; // 全局的用户数据
req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
if (!req.sessionID) {
req.sessionID = uuid.v4();
}
next();
});
// dispatcher
try {
const user = require('./doraemon/middleware/user');
const setYohoData = require('./doraemon/middleware/set-yoho-data');
const errorHanlder = require('./doraemon/middleware/error-handler');
const setPageInfo = require('./doraemon/middleware/set-pageinfo');
const layoutTools = require('./doraemon/middleware/layout-tools');
// YOHO 前置中间件
app.use(setYohoData());
app.use(user());
app.use(setPageInfo());
app.use(layoutTools());
require('./doraemon/middleware/ssr')(app);
require('./dispatch')(app);
app.all('*', errorHanlder.notFound()); // 404
// YOHO 后置中间件
app.use(errorHanlder.serverError());
} catch (err) {
logger.error(err);
}
// listener
app.listen(config.port, function() {
logger.info(`worker is started at ${config.port}`);
});
}
... ...
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const cluster = require('cluster');
const express = require('express');
const chokidar = require('chokidar');
const EventSource = require('eventsource');
const {createApp} = require('./create-app.js');
const {createBundleRenderer} = require('vue-server-renderer');
const {devServer, readFile, publish} = require('./build/dev-server.js');
const watcher = {
paths: ['./apps', './create-app.js', './doraemon', './config', './utils'],
options: {}
};
let renderer;
let realyPromise;
let template = fs.readFileSync(path.join(__dirname, './src/index.html'), 'utf-8');
if (cluster.isMaster) {
const masterApp = express();
realyPromise = devServer(masterApp, params => {
renderer = createBundleRenderer(params.bundle, Object.assign(params.options, {
runInNewContext: false,
template
}));
});
let childWorker = cluster.fork();
cluster.on('message', (worker, msg) => {
if (msg.action === 'ssr_request') {
realyPromise.then(() => {
renderer.renderToString(msg.context, (err, html) => {
if (err) {
console.error('ssr error:', err);
}
worker.send({action: 'ssr_request', html: html || err.toString()});
});
});
} else if (msg.action === 'ssr_static_file') {
worker.send({
action: 'ssr_static_file',
file: readFile(msg.path),
path: msg.path
});
}
});
chokidar.watch(watcher.paths, watcher.options).on('change', pathStr => {
console.log(`${pathStr} changed`);
childWorker && childWorker.kill();
childWorker = cluster.fork().on('listening', address => {
console.log(`worker is restarted at ${address.port}`);
publish({action: 'reload'});
console.log('client is refresh');
});
});
masterApp.listen(6005, () => {
console.log('master is started');
});
} else {
const app = express();
app.get(/\.(js|css|jpg|gif|jpeg|png|eot|svg|ttf|woff|hot-update\.json)$/, (req, res) => {
process.send({action: 'ssr_static_file', path: req.path});
let event = msg => {
if (msg.action === 'ssr_static_file' && msg.path === req.path) {
process.removeListener('message', event);
return res.end(msg.file);
}
};
process.on('message', event);
});
let es = new EventSource('http://localhost:6005/__webpack_hmr');
let clients = {};
let clientId = 0;
es.onmessage = (event) => {
_.each(clients, client => {
client.write('data: ' + event.data + '\n\n');
});
};
app.use('/__webpack_hmr', (req, res) => {
req.socket.setKeepAlive(true);
res.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'text/event-stream;charset=utf-8',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
'X-Accel-Buffering': 'no'
});
res.write('\n');
let id = clientId++;
clients[id] = res;
req.on('close', function() {
delete clients[id];
});
});
createApp(app);
}
... ...
const fs = require('fs');
const path = require('path');
const {createBundleRenderer} = require('vue-server-renderer');
const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV;
let renderer;
let template = fs.readFileSync(path.join(__dirname, '../../src/index.html'), 'utf-8');
const render = (req, res) => {
let context = {
url: req.url,
title: 'BLK!'
};
renderer.renderToString(context, (err, html) => {
if (err) {
console.error('error:', err);
}
return res.send(html);
});
};
if (!isDev) {
const serverBundle = require('../../bundle/vue-ssr-server-bundle.json');
const clientManifest = require('../../bundle/vue-ssr-client-manifest.json');
renderer = createBundleRenderer(serverBundle, {
runInNewContext: false,
template,
clientManifest
});
}
const ssrRender = isDev ? (req, res) => {
process.send({action: 'ssr_request', context: {
url: req.url,
title: 'BLK!'
}});
process.on('message', msg => {
if (msg.action === 'ssr_request') {
return res.end(msg.html);
}
});
} : render;
module.exports = app => {
app.get(/\/product\/pro_([\d]+)_([\d]+)\/(.*).html/, ssrRender);
};
... ...
... ... @@ -9,7 +9,9 @@
},
"scripts": {
"start": "node app.js",
"dev": "nodemon -e js,hbs -i public/ app.js",
"dev": "node dev.js",
"client": "NODE_ENV=production webpack --config ./build/webpack.client.conf.js",
"server": "NODE_ENV=production webpack --config ./build/webpack.server.conf.js",
"static": "webpack-dev-server --config ./public/build/webpack.dev.config.js",
"build": "NODE_ENV=production webpack --config ./public/build/webpack.prod.config.js",
"performance": "NODE_ENV=performance webpack --config ./public/build/webpack.prod.config.js",
... ... @@ -22,6 +24,7 @@
},
"license": "MIT",
"dependencies": {
"axios": "^0.16.2",
"babel-polyfill": "^6.23.0",
"babel-runtime": "^6.11.6",
"bluebird": "^3.4.2",
... ... @@ -31,15 +34,18 @@
"cookie-parser": "^1.4.3",
"express": "^4.14.0",
"express-session": "^1.14.1",
"global": "^4.3.2",
"happypack": "^3.1.0",
"influxdb-winston": "^1.0.1",
"lodash": "^4.15.0",
"lodash-cli": "^4.17.4",
"memcached": "^2.2.1",
"mint-ui": "^1.0.2",
"moment": "^2.14.1",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
"request-promise": "^3.0.0",
"sass-loader": "^6.0.6",
"serve-favicon": "^2.3.0",
"uuid": "^2.0.2",
"vue": "^2.4.2",
... ... @@ -51,7 +57,7 @@
"yoho-cookie": "1.2.0",
"yoho-jquery": "^2.2.4",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "0.2.17",
"yoho-node-lib": "0.2.29",
"yoho-qs": "1.0.1",
"yoho-store": "^1.3.20"
},
... ... @@ -60,20 +66,28 @@
"babel-core": "^6.24.1",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.0.0",
"babel-plugin-transform-runtime": "^6.12.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.4.0",
"babel-preset-es2015": "^6.14.0",
"chokidar": "^1.7.0",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.1",
"eslint": "^3.3.1",
"eslint-config-yoho": "^1.0.1",
"eslint-plugin-html": "^1.5.2",
"eventsource": "^1.0.5",
"extract-text-webpack-plugin": "^2.1.0",
"fastclick": "^1.0.6",
"file-loader": "^0.11.1",
"friendly-errors-webpack-plugin": "^1.6.1",
"handlebars-loader": "^1.5.0",
"husky": "^0.11.6",
"jquery": "2.2.4",
"memory-fs": "^0.4.1",
"node-sass": "^4.5.3",
"nodemon": "^1.10.2",
"postcss-assets": "^4.1.0",
... ... @@ -86,30 +100,34 @@
"postcss-loader": "^2.0.5",
"postcss-position": "^0.5.0",
"postcss-pxtorem": "^3.3.1",
"postcss-scss": "^1.0.0",
"postcss-short": "^1.4.0",
"postcss-sprites": "^4.2.1",
"postcss-use": "^2.3.0",
"precss": "^1.4.0",
"sass-loader": "^6.0.6",
"scss-loader": "0.0.1",
"shelljs": "^0.7.3",
"style-loader": "^0.17.0",
"stylelint": "^7.1.0",
"stylelint-config-yoho": "^1.2.7",
"stylelint-processor-html": "^1.0.0",
"uglifyjs-webpack-plugin": "^0.4.6",
"vue-hot-reload-api": "^1.2.0",
"vue-html-loader": "^1.2.4",
"vue-infinite-scroll": "^2.0.1",
"vue-lazyload": "^1.0.6",
"vue-loader": "^13.0.2",
"vue-router": "^2.7.0",
"vue-server-renderer": "^2.4.2",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.4.2",
"vuex": "^2.4.0",
"webpack": "3.3",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dashboard": "^0.1.8",
"webpack-dev-middleware": "^1.12.0",
"webpack-dev-server": "^2.6.1",
"webpack-hot-middleware": "^2.18.2",
"webpack-merge": "^4.1.0",
"webpack-node-externals": "^1.6.0",
"webpack-stream": "^3.1.0",
"webpack-uglify-parallel": "^0.1.3",
"webpack-visualizer-plugin": "^0.1.11"
... ...
... ... @@ -10,7 +10,6 @@
*/
import cookie from 'yoho-cookie';
import store from 'yoho-store';
import tip from 'common/tip';
/* 空方法 */
const nullFun = () => {};
... ...
import Vue from 'vue';
import App from './app.vue';
import {createRouter} from './router';
import {createStore} from './store';
import titleMixin from './mixins/title';
import pluginCore from './plugins/core';
Vue.use(pluginCore);
Vue.mixin(titleMixin);
export function createApp() {
const router = createRouter();
const store = createStore();
const app = new Vue({
router,
store,
render: h => h(App)
});
return {app, router, store};
}
... ...
<template>
<div id="app" class="page">
<header-box></header-box>
<div class="page-content">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
};
</script>
<style>
</style>
... ...
import Layout from './layout';
export default {
Layout
};
... ...
<template>
<div class="blk-header-wrap" v-if="showHeader" :class="[{'is-fixed': fixed}, className]">
<div class="blk-header">
<div class="blk-header-left">
<slot name="left">
<i class="icon icon-back go-back-btn" @click="goBack"></i>
</slot>
</div>
<div class="blk-header-right">
<slot name="right"></slot>
</div>
<div class="blk-header-main">
<span class="blk-header-title">{{title}}</span>
</div>
</div>
<div class="blk-header-gap" v-if="!fixed"></div>
</div>
</template>
<script>
export default {
name: 'HeaderBox',
props: {
title: String,
className: [String, Object, Array],
fixed: Boolean,
scrollFix: Boolean,
must: {
type: Boolean,
default: true
}
},
data() {
return {
showHeader: true
};
},
methods: {
goBack() {
this.$yoho.goBack({}, function() {}, function() {});
}
},
mounted() {
if (this.$yoho.isYohoBuy) {
this.showHeader = this.must; // must为true 必须显示,否则为false
}
}
};
</script>
<style lang="scss">
@import "~header.scss";
.blk-header-wrap.hide {
.blk-header {
display: none;
}
}
.blk-header-wrap.ghost {
.blk-header {
background-color: rgba(255, 255, 255, 0);
transition: 0.3s all;
border-bottom: 0;
}
.blk-header-title {
opacity: 0;
}
}
.blk-header-wrap.ghost-2 {
.blk-header {
background-color: rgba(255, 255, 255, 0.4);
transition: 0.3s all;
border-bottom: 0;
}
.blk-header-title {
opacity: 0.4;
}
}
.blk-header-wrap.ghost-3 {
.blk-header {
background-color: rgba(255, 255, 255, 0.7);
transition: 0.3s all;
border-bottom: 0;
}
.blk-header-title {
opacity: 0.7;
}
}
.blk-header {
box-sizing: content-box;
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 210;
padding: 0 34px;
height: $header-height;
max-width: 750px;
margin-left: auto;
margin-right: auto;
line-height: $header-height;
font-size: $header-font-size;
font-weight: bold;
background-color: #fff;
border-bottom: 1px solid #eee;
color: #000;
.icon,
.blk-header-title {
vertical-align: middle;
}
.blk-header-right {
margin-right: -32px;
}
.icon {
min-width: $header-height;
min-height: $header-height;
line-height: $header-height;
margin-left: -32px;
text-indent: 32px;
display: inline-block;
}
.go-back-btn {
&:active {
background: #ccc;
opacity: 0.5;
}
}
}
.blk-header-main {
display: block;
text-align: center;
margin-left: auto;
margin-right: auto;
font-size: $header-font-size;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
position: absolute;
left: 0;
right: 0;
z-index: -1;
}
.blk-header-left {
float: left;
font-size: 64px;
}
.blk-header-right {
float: right;
font-size: 45px;
span {
margin-left: 30px;
}
.right-btn {
font-size: 17PX;
margin-right: 30px;
}
}
.blk-header-gap {
height: calc($header-height + 2);
background-color: transparent;
}
</style>
... ...
import HeaderBox from './header-box';
export default {
HeaderBox
};
... ...
export default {
development: {
baseURL: '/',
axiosResponseType: 'json',
},
production: {
baseURL: '/',
axiosResponseType: 'json',
}
};
... ...
import Vue from 'vue';
import {createApp} from './app';
import yoho from '../public/js/yoho';
if (process.env.NODE_ENV === 'development') {
yoho.isApp = true;
}
const {app, router} = createApp();
Vue.prop('yoho', yoho);
router.onReady(() => {
app.$mount('#app');
});
... ...
import {createApp} from './app';
const {app, router} = createApp();
export default context => {
return new Promise((resolve, reject) => {
const {url} = context;
const route = router.resolve(url).route;
if (url !== route.fullPath && url !== route.redirectedFrom) {
reject({url: route.fullPath});
}
context.state = {name: 'chenfeng'};
router.push(url);
router.onReady(() => {
const matchedComponents = router.getMatchedComponents();
if (!matchedComponents.length) {
reject({code: 404});
}
resolve(app);
});
});
};
... ...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<meta name="keywords" content="">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta content="telephone=no" name="format-detection">
<meta content="email=no" name="format-detection">
<script type="text/javascript">
(function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=750){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/750)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window);
if (/YohoBuy/i.test(navigator.userAgent || '')) {
window.appBaseLogs = {device: {},status: [],events: []}
}
</script>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
\ No newline at end of file
... ...
const getTitle = vue => {
const {title} = vue.$options;
if (title) {
return typeof title === 'function' ? title.call(vue) : title;
}
};
const serverTitleMixin = {
created() {
const title = getTitle(this);
if (title) {
this.$ssrContext.title = title;
}
}
};
const clientTitleMixin = {
mounted() {
const title = getTitle(this);
if (title) {
document.title = title;
}
}
};
export default process.env.VUE_ENV === 'server' ?
serverTitleMixin :
clientTitleMixin;
... ...
import product from './product';
export default {
product
};
... ...
<template>
<div>
</div>
</template>
<script>
export default {
name: 'ProductDetail',
title() {
return '商品详情页';
}
};
</script>
<style>
</style>
... ...
export default {
path: '/:pids(pro_\\d+_\\d+)/:name(.*?\\.html)',
name: 'detail',
component: () => import(/* webpackChunkName: "detail" */ './detail')
};
... ...
import detail from './detail';
export default {
detail
};
... ...
/**
* 插件
*/
import store from 'yoho-store';
import cookie from 'yoho-cookie';
import components from '../components';
import axios from 'axios';
import config from 'config';
import _ from 'lodash/core';
export default {
loadGlobalComponents(Vue) {
_.each(components, componentModules => {
_.each(componentModules, component => {
if (component.length) {
Vue.component(component[0], component[1]);
} else {
Vue.component(component.name, component);
}
});
});
},
defineVueProp(Vue) {
Vue.prop = (key, value) => {
Vue[`$${key}`] = Vue.prototype[`$${key}`] = value;
};
},
install(Vue) {
// 定义Vue全局属性
this.defineVueProp(Vue);
// 加载核心组件
this.loadGlobalComponents(Vue);
// 附加Vue原型属性
Vue.prop('config', config[process.env.NODE_ENV]);
Vue.prop('store', store);
Vue.prop('cookie', cookie);
// 设置axios默认参数
axios.defaults.baseURL = Vue.$config.axiosBaseUrl;
axios.defaults.responseType = Vue.$config.axiosResponseType;
axios.interceptors.response.use(response => {
if (response.status >= 200 && response.status < 300) {
return response;
}
return Promise.reject({response});
}, error => {
return Promise.reject(error);
});
}
};
... ...
import Vue from 'vue';
import Router from 'vue-router';
import pages from '../pages';
import _ from 'lodash/core';
Vue.use(Router);
const loadRoutes = (rous, paths, children) => {
if (_.has(rous, 'path')) {
let ps = _.flattenDeep(paths).filter(p => p);
if (_.last(ps) === rous.name) {
ps.splice(ps.length - 1, 1);
}
if (!children) {
if (rous.path) {
rous.path = '/' + ps.join('/') + (rous.path[0] === '/' ? '' : '/') + rous.path;
} else {
rous.path = ps.join('/') + '.html';
}
}
rous.name = _.concat(ps, [rous.name]).join('.');
if (rous.children) {
_.each(rous.children, child => loadRoutes(child, [paths, child.name], true));
return [rous];
}
return [rous];
}
if (rous.length) {
return _.map(rous, r => {
return loadRoutes(r, [paths]);
});
} else {
return _.map(rous, (rou, k) => {
return loadRoutes(rou, [paths, k]);
});
}
};
export function createRouter() {
let routes = _.flattenDeep(loadRoutes(pages));
return new Router({
mode: 'history',
routes
});
}
... ...
$header-height: 88px;
$header-font-size: 17PX;
... ...
import {
FILTER_ADD_PARAMS,
FILTER_MINUS_PARAMS,
FILTER_LIST_SUCCESS
} from './types';
export const filter = {
state: {
list: [],
isFetching: false
},
mutations: {
[FILTER_ADD_PARAMS](state, params) {
console.log(params);
},
[FILTER_MINUS_PARAMS](state, params) {
console.log(params);
},
[FILTER_LIST_SUCCESS](state, params) {
console.log(params);
}
},
actions: {
}
};
... ...
export const FILTER_ADD_PARAMS = 'FILTER_ADD_PARAMS';
export const FILTER_MINUS_PARAMS = 'FILTER_MINUS_PARAMS';
export const FILTER_LIST_SUCCESS = 'FILTER_LIST_SUCCESS';
... ...
import Vue from 'vue';
import Vuex from 'vuex';
import {filter} from './filter';
Vue.use(Vuex);
export function createStore() {
return new Vuex.Store({
modules: {
filter
},
strict: process.env.NODE_ENV !== 'production'
});
}
... ...
... ... @@ -315,6 +315,13 @@ aws4@^1.2.1:
version "1.6.0"
resolved "http://npm.yoho.cn/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
axios@^0.16.2:
version "0.16.2"
resolved "http://npm.yoho.cn/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d"
dependencies:
follow-redirects "^1.2.3"
is-buffer "^1.1.5"
babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
version "6.22.0"
resolved "http://npm.yoho.cn/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
... ... @@ -494,10 +501,22 @@ babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
babel-plugin-syntax-dynamic-import@^6.18.0:
version "6.18.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
babel-plugin-syntax-trailing-function-commas@^6.22.0:
version "6.22.0"
resolved "http://npm.yoho.cn/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
... ... @@ -686,13 +705,20 @@ babel-plugin-transform-exponentiation-operator@^6.22.0:
babel-plugin-syntax-exponentiation-operator "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-object-rest-spread@^6.26.0:
version "6.26.0"
resolved "http://npm.yoho.cn/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.26.0"
babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1:
version "6.24.1"
resolved "http://npm.yoho.cn/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418"
dependencies:
regenerator-transform "0.9.11"
babel-plugin-transform-runtime@^6.12.0:
babel-plugin-transform-runtime@^6.23.0:
version "6.23.0"
resolved "http://npm.yoho.cn/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee"
dependencies:
... ... @@ -705,6 +731,12 @@ babel-plugin-transform-strict-mode@^6.24.1:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-vue-jsx@^3.5.0:
version "3.5.0"
resolved "http://npm.yoho.cn/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-3.5.0.tgz#6b1ad29351ad753919403675f0bf8b2a43e17671"
dependencies:
esutils "^2.0.2"
babel-polyfill@^6.23.0:
version "6.23.0"
resolved "http://npm.yoho.cn/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
... ... @@ -789,13 +821,20 @@ babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0:
babel-runtime@^6.11.6, babel-runtime@^6.22.0:
version "6.23.0"
resolved "http://npm.yoho.cn/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
babel-runtime@^6.18.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "http://npm.yoho.cn/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
babel-template@^6.24.1, babel-template@^6.25.0:
version "6.25.0"
resolved "http://npm.yoho.cn/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071"
... ... @@ -1373,6 +1412,12 @@ cloneable-readable@^1.0.0:
process-nextick-args "^1.0.6"
through2 "^2.0.1"
closure-compiler@0.2.12:
version "0.2.12"
resolved "http://registry.npm.taobao.org/closure-compiler/download/closure-compiler-0.2.12.tgz#6c3087cad12742c79e47f0ce50e87af91cf8e171"
dependencies:
google-closure-compiler "20150901.x"
co@^4.6.0:
version "4.6.0"
resolved "http://npm.yoho.cn/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
... ... @@ -1988,7 +2033,7 @@ debug@2.6.7:
dependencies:
ms "2.0.0"
debug@2.6.8, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.0, debug@^2.6.6, debug@^2.6.8:
debug@2.6.8, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.5, debug@^2.6.0, debug@^2.6.6, debug@^2.6.8:
version "2.6.8"
resolved "http://npm.yoho.cn/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
dependencies:
... ... @@ -2133,6 +2178,10 @@ dom-serializer@0:
domelementtype "~1.1.1"
entities "~1.1.1"
dom-walk@^0.1.0:
version "0.1.1"
resolved "http://registry.npm.taobao.org/dom-walk/download/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
domain-browser@^1.1.1:
version "1.1.7"
resolved "http://npm.yoho.cn/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
... ... @@ -2321,6 +2370,12 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
error-stack-parser@^2.0.0:
version "2.0.1"
resolved "http://registry.npm.taobao.org/error-stack-parser/download/error-stack-parser-2.0.1.tgz#a3202b8fb03114aa9b40a0e3669e48b2b65a010a"
dependencies:
stackframe "^1.0.3"
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
version "0.10.24"
resolved "http://npm.yoho.cn/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14"
... ... @@ -2587,6 +2642,12 @@ eventsource@0.1.6:
dependencies:
original ">=0.0.5"
eventsource@^1.0.5:
version "1.0.5"
resolved "http://registry.npm.taobao.org/eventsource/download/eventsource-1.0.5.tgz#1f012c9df0bd8832fd6b1744fea00ccdd479f046"
dependencies:
original "^1.0.0"
evp_bytestokey@^1.0.0:
version "1.0.0"
resolved "http://npm.yoho.cn/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
... ... @@ -2858,6 +2919,12 @@ flatten@^1.0.2:
version "1.0.2"
resolved "http://npm.yoho.cn/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
follow-redirects@^1.2.3:
version "1.2.4"
resolved "http://npm.yoho.cn/follow-redirects/-/follow-redirects-1.2.4.tgz#355e8f4d16876b43f577b0d5ce2668b9723214ea"
dependencies:
debug "^2.4.5"
for-in@^0.1.3:
version "0.1.8"
resolved "http://npm.yoho.cn/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
... ... @@ -2906,6 +2973,14 @@ fresh@0.5.0:
version "0.5.0"
resolved "http://npm.yoho.cn/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
friendly-errors-webpack-plugin@^1.6.1:
version "1.6.1"
resolved "http://registry.npm.taobao.org/friendly-errors-webpack-plugin/download/friendly-errors-webpack-plugin-1.6.1.tgz#e32781c4722f546a06a9b5d7a7cfa28520375d70"
dependencies:
chalk "^1.1.3"
error-stack-parser "^2.0.0"
string-length "^1.0.1"
from@~0:
version "0.1.7"
resolved "http://npm.yoho.cn/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
... ... @@ -3068,6 +3143,17 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
glob@7.1.1, glob@^7.0.0, glob@^7.0.3:
version "7.1.1"
resolved "http://registry.npm.taobao.org/glob/download/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.2"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^5.0.15, glob@^5.0.3:
version "5.0.15"
resolved "http://npm.yoho.cn/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
... ... @@ -3088,7 +3174,7 @@ glob@^6.0.4:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
version "7.1.2"
resolved "http://npm.yoho.cn/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
... ... @@ -3099,6 +3185,13 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
global@^4.3.2:
version "4.3.2"
resolved "http://npm.yoho.cn/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
dependencies:
min-document "^2.19.0"
process "~0.5.1"
globals@^9.0.0, globals@^9.14.0:
version "9.18.0"
resolved "http://npm.yoho.cn/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
... ... @@ -3153,6 +3246,10 @@ glogg@^1.0.0:
dependencies:
sparkles "^1.0.0"
google-closure-compiler@20150901.x:
version "20150901.0.0"
resolved "http://registry.npm.taobao.org/google-closure-compiler/download/google-closure-compiler-20150901.0.0.tgz#3d01c6cade65790a9bfb4e30b2158b7635acbade"
got@^3.2.0:
version "3.3.1"
resolved "http://npm.yoho.cn/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
... ... @@ -4098,6 +4195,16 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
lodash-cli@^4.17.4:
version "4.17.4"
resolved "http://npm.yoho.cn/lodash-cli/-/lodash-cli-4.17.4.tgz#23b727cd0e91e28484fafda1521900a8a811df81"
dependencies:
closure-compiler "0.2.12"
glob "7.1.1"
lodash "4.17.4"
semver "5.3.0"
uglify-js "2.7.5"
lodash._arraymap@^3.0.0:
version "3.0.0"
resolved "http://npm.yoho.cn/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz#1a8fd0f4c0df4b61dea076d717cdc97f0a3c3e66"
... ... @@ -4176,7 +4283,7 @@ lodash._reevaluate@^3.0.0:
version "3.0.0"
resolved "http://npm.yoho.cn/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
lodash._reinterpolate@^3.0.0:
lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "http://npm.yoho.cn/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
... ... @@ -4310,6 +4417,13 @@ lodash.template@^3.0.0:
lodash.restparam "^3.0.0"
lodash.templatesettings "^3.0.0"
lodash.template@^4.4.0:
version "4.4.0"
resolved "http://npm.yoho.cn/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.templatesettings "^4.0.0"
lodash.templatesettings@^3.0.0:
version "3.1.1"
resolved "http://npm.yoho.cn/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
... ... @@ -4317,18 +4431,24 @@ lodash.templatesettings@^3.0.0:
lodash._reinterpolate "^3.0.0"
lodash.escape "^3.0.0"
lodash.templatesettings@^4.0.0:
version "4.1.0"
resolved "http://npm.yoho.cn/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "http://npm.yoho.cn/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@4.17.4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4:
version "4.17.4"
resolved "http://npm.yoho.cn/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
lodash@^3.10.1:
version "3.10.1"
resolved "http://npm.yoho.cn/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1, lodash@~4.17.4:
version "4.17.4"
resolved "http://npm.yoho.cn/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
log-symbols@^1.0.2:
version "1.0.2"
resolved "http://npm.yoho.cn/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
... ... @@ -4461,7 +4581,7 @@ memory-fs@^0.3.0, memory-fs@~0.3.0:
errno "^0.1.3"
readable-stream "^2.0.1"
memory-fs@^0.4.0, memory-fs@~0.4.1:
memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1:
version "0.4.1"
resolved "http://npm.yoho.cn/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
dependencies:
... ... @@ -4534,6 +4654,12 @@ mimic-fn@^1.0.0:
version "1.1.0"
resolved "http://npm.yoho.cn/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
min-document@^2.19.0:
version "2.19.0"
resolved "http://registry.npm.taobao.org/min-document/download/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
dependencies:
dom-walk "^0.1.0"
minimalistic-assert@^1.0.0:
version "1.0.0"
resolved "http://npm.yoho.cn/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
... ... @@ -5070,7 +5196,7 @@ options@>=0.0.5:
version "0.0.6"
resolved "http://npm.yoho.cn/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
original@>=0.0.5:
original@>=0.0.5, original@^1.0.0:
version "1.0.0"
resolved "http://npm.yoho.cn/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b"
dependencies:
... ... @@ -5823,12 +5949,6 @@ postcss-scss@^0.4.0:
dependencies:
postcss "^5.2.13"
postcss-scss@^1.0.0:
version "1.0.2"
resolved "http://npm.yoho.cn/postcss-scss/-/postcss-scss-1.0.2.tgz#ff45cf3354b879ee89a4eb68680f46ac9bb14f94"
dependencies:
postcss "^6.0.3"
postcss-selector-matches@^2.0.0:
version "2.0.5"
resolved "http://npm.yoho.cn/postcss-selector-matches/-/postcss-selector-matches-2.0.5.tgz#fa0f43be57b68e77aa4cd11807023492a131027f"
... ... @@ -5981,7 +6101,7 @@ postcss@^5.0, postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12,
source-map "^0.5.6"
supports-color "^3.2.3"
postcss@^6.0.1, postcss@^6.0.2, postcss@^6.0.3, postcss@^6.0.6:
postcss@^6.0.1, postcss@^6.0.2, postcss@^6.0.6:
version "6.0.6"
resolved "http://npm.yoho.cn/postcss/-/postcss-6.0.6.tgz#bba4d58e884fc78c840d1539e10eddaabb8f73bd"
dependencies:
... ... @@ -6038,6 +6158,10 @@ process@^0.11.0, process@^0.11.1:
version "0.11.10"
resolved "http://npm.yoho.cn/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
process@~0.5.1:
version "0.5.2"
resolved "http://registry.npm.taobao.org/process/download/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
progress@^1.1.8, progress@~1.1.8:
version "1.1.8"
resolved "http://npm.yoho.cn/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
... ... @@ -6118,7 +6242,7 @@ querystring-es3@^0.2.0:
version "0.2.1"
resolved "http://npm.yoho.cn/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
querystring@0.2.0:
querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "http://npm.yoho.cn/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
... ... @@ -6341,6 +6465,10 @@ regenerator-runtime@^0.10.0:
version "0.10.5"
resolved "http://npm.yoho.cn/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
regenerator-runtime@^0.11.0:
version "0.11.0"
resolved "http://npm.yoho.cn/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
regenerator-transform@0.9.11:
version "0.9.11"
resolved "http://npm.yoho.cn/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283"
... ... @@ -6529,7 +6657,7 @@ resolve@1.1.7:
version "1.1.7"
resolved "http://npm.yoho.cn/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.3:
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.3:
version "1.3.3"
resolved "http://npm.yoho.cn/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
dependencies:
... ... @@ -6672,10 +6800,6 @@ schema-utils@^0.3.0:
dependencies:
ajv "^5.0.0"
scss-loader@0.0.1:
version "0.0.1"
resolved "http://npm.yoho.cn/scss-loader/-/scss-loader-0.0.1.tgz#eae017b9e0f38c12a532db25c220b902fb34e671"
scss-tokenizer@^0.2.3:
version "0.2.3"
resolved "http://npm.yoho.cn/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
... ... @@ -6699,7 +6823,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@~5.3.0:
"semver@2 || 3 || 4 || 5", semver@5.3.0, semver@^5.0.3, semver@^5.3.0, semver@~5.3.0:
version "5.3.0"
resolved "http://npm.yoho.cn/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
... ... @@ -6740,6 +6864,10 @@ serialize-error@^2.1.0:
version "2.1.0"
resolved "http://npm.yoho.cn/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a"
serialize-javascript@^1.3.0:
version "1.4.0"
resolved "http://npm.yoho.cn/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005"
serve-favicon@^2.3.0:
version "2.4.3"
resolved "http://npm.yoho.cn/serve-favicon/-/serve-favicon-2.4.3.tgz#5986b17b0502642b641c21f818b1acce32025d23"
... ... @@ -6950,7 +7078,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4, source-map@~0.4.1:
dependencies:
amdefine ">=0.0.4"
"source-map@>= 0.1.2", source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
source-map@0.5.6, "source-map@>= 0.1.2", source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
version "0.5.6"
resolved "http://npm.yoho.cn/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
... ... @@ -7049,6 +7177,10 @@ stack-trace@0.0.x:
version "0.0.10"
resolved "http://npm.yoho.cn/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
stackframe@^1.0.3:
version "1.0.4"
resolved "http://registry.npm.taobao.org/stackframe/download/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b"
static-eval@~0.2.0:
version "0.2.4"
resolved "http://npm.yoho.cn/static-eval/-/static-eval-0.2.4.tgz#b7d34d838937b969f9641ca07d48f8ede263ea7b"
... ... @@ -7123,7 +7255,7 @@ string-hash@^1.1.0:
version "1.1.3"
resolved "http://npm.yoho.cn/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
string-length@^1.0.0:
string-length@^1.0.0, string-length@^1.0.1:
version "1.0.1"
resolved "http://npm.yoho.cn/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
dependencies:
... ... @@ -7463,6 +7595,10 @@ time-stamp@^1.0.0:
version "1.1.0"
resolved "http://npm.yoho.cn/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
time-stamp@^2.0.0:
version "2.0.0"
resolved "http://npm.yoho.cn/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357"
timed-out@^2.0.0:
version "2.0.0"
resolved "http://npm.yoho.cn/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
... ... @@ -7564,6 +7700,15 @@ uglify-js@2.6.x:
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
uglify-js@2.7.5, uglify-js@~2.7.3:
version "2.7.5"
resolved "http://npm.yoho.cn/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
dependencies:
async "~0.2.6"
source-map "~0.5.1"
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
uglify-js@^2.6, uglify-js@^2.6.0, uglify-js@^2.6.2, uglify-js@^2.8.29:
version "2.8.29"
resolved "http://npm.yoho.cn/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
... ... @@ -7573,15 +7718,6 @@ uglify-js@^2.6, uglify-js@^2.6.0, uglify-js@^2.6.2, uglify-js@^2.8.29:
optionalDependencies:
uglify-to-browserify "~1.0.0"
uglify-js@~2.7.3:
version "2.7.5"
resolved "http://npm.yoho.cn/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
dependencies:
async "~0.2.6"
source-map "~0.5.1"
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "http://npm.yoho.cn/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
... ... @@ -7701,7 +7837,7 @@ uuid@^2.0.1, uuid@^2.0.2:
version "2.0.3"
resolved "http://npm.yoho.cn/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
uuid@^3.0.0:
uuid@^3.0.0, uuid@^3.0.1:
version "3.1.0"
resolved "http://npm.yoho.cn/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
... ... @@ -7846,6 +7982,23 @@ vue-popup@0.1.13, vue-popup@^0.1.13:
version "0.1.13"
resolved "http://npm.yoho.cn/vue-popup/-/vue-popup-0.1.13.tgz#fc03251ec17751b520c79c41ad4c69f8889833db"
vue-router@^2.7.0:
version "2.7.0"
resolved "http://npm.yoho.cn/vue-router/-/vue-router-2.7.0.tgz#16d424493aa51c3c8cce8b7c7210ea4c3a89aff1"
vue-server-renderer@^2.4.2:
version "2.4.2"
resolved "http://npm.yoho.cn/vue-server-renderer/-/vue-server-renderer-2.4.2.tgz#0ba0f984181ea1c455362b09bddf60bc0e0a03fa"
dependencies:
chalk "^1.1.3"
hash-sum "^1.0.2"
he "^1.1.0"
lodash.template "^4.4.0"
lodash.uniq "^4.5.0"
resolve "^1.2.0"
serialize-javascript "^1.3.0"
source-map "0.5.6"
vue-style-loader@^3.0.0, vue-style-loader@^3.0.1:
version "3.0.1"
resolved "http://npm.yoho.cn/vue-style-loader/-/vue-style-loader-3.0.1.tgz#c8b639bb2f24baf9d78274dc17e4f264c1deda08"
... ... @@ -7893,6 +8046,10 @@ vue@^2.4.2:
version "2.4.2"
resolved "http://npm.yoho.cn/vue/-/vue-2.4.2.tgz#a9855261f191c978cc0dc1150531b8d08149b58c"
vuex@^2.4.0:
version "2.4.0"
resolved "http://npm.yoho.cn/vuex/-/vuex-2.4.0.tgz#e1d0430646282b40007fdd06ec6ae88a9f5a1e14"
walk@^2.3.9:
version "2.3.9"
resolved "http://npm.yoho.cn/walk/-/walk-2.3.9.tgz#31b4db6678f2ae01c39ea9fb8725a9031e558a7b"
... ... @@ -7956,14 +8113,15 @@ webpack-dashboard@^0.1.8:
socket.io-client "^1.4.8"
webpack "^1.13.1"
webpack-dev-middleware@^1.11.0:
version "1.11.0"
resolved "http://npm.yoho.cn/webpack-dev-middleware/-/webpack-dev-middleware-1.11.0.tgz#09691d0973a30ad1f82ac73a12e2087f0a4754f9"
webpack-dev-middleware@^1.11.0, webpack-dev-middleware@^1.12.0:
version "1.12.0"
resolved "http://npm.yoho.cn/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709"
dependencies:
memory-fs "~0.4.1"
mime "^1.3.4"
path-is-absolute "^1.0.0"
range-parser "^1.0.3"
time-stamp "^2.0.0"
webpack-dev-server@^2.6.1:
version "2.6.1"
... ... @@ -7992,12 +8150,25 @@ webpack-dev-server@^2.6.1:
webpack-dev-middleware "^1.11.0"
yargs "^6.0.0"
webpack-hot-middleware@^2.18.2:
version "2.18.2"
resolved "http://npm.yoho.cn/webpack-hot-middleware/-/webpack-hot-middleware-2.18.2.tgz#84dee643f037c3d59c9de142548430371aa8d3b2"
dependencies:
ansi-html "0.0.7"
html-entities "^1.2.0"
querystring "^0.2.0"
strip-ansi "^3.0.0"
webpack-merge@^4.1.0:
version "4.1.0"
resolved "http://npm.yoho.cn/webpack-merge/-/webpack-merge-4.1.0.tgz#6ad72223b3e0b837e531e4597c199f909361511e"
dependencies:
lodash "^4.17.4"
webpack-node-externals@^1.6.0:
version "1.6.0"
resolved "http://npm.yoho.cn/webpack-node-externals/-/webpack-node-externals-1.6.0.tgz#232c62ec6092b100635a3d29d83c1747128df9bd"
webpack-sources@^1.0.1:
version "1.0.1"
resolved "http://npm.yoho.cn/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"
... ... @@ -8358,9 +8529,9 @@ yoho-md5@^2.0.0:
version "2.0.0"
resolved "http://npm.yoho.cn/yoho-md5/-/yoho-md5-2.0.0.tgz#e801a5cce8e08f5d7211e9a2e789ea7275eb9332"
yoho-node-lib@0.2.17:
version "0.2.17"
resolved "http://npm.yoho.cn/yoho-node-lib/-/yoho-node-lib-0.2.17.tgz#b01f16fe8967f1d768ceab757ada9d394f45e0ef"
yoho-node-lib@0.2.29:
version "0.2.29"
resolved "http://npm.yoho.cn/yoho-node-lib/-/yoho-node-lib-0.2.29.tgz#66a9921becedb5e336f1a573fba9d38bd8a82135"
dependencies:
bluebird "^3.4.0"
handlebars "^4.0.5"
... ... @@ -8370,6 +8541,7 @@ yoho-node-lib@0.2.17:
memory-cache "^0.1.6"
moment "^2.13.0"
request-promise "^3.0.0"
uuid "^3.0.1"
walk "^2.3.9"
winston "^2.2.0"
winston-daily-rotate-file "^1.1.1"
... ...