├── .gitignore
├── README.md
├── client
├── .babelrc
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── Dockerfile
├── build
│ ├── build.js
│ ├── check-versions.js
│ ├── logo.png
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config
│ ├── dev.env.js
│ ├── index.js
│ ├── nginx.conf
│ └── prod.env.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── Header.vue
│ │ ├── ManufacturerForm.vue
│ │ └── products
│ │ │ ├── ProductButton.vue
│ │ │ ├── ProductDetail.vue
│ │ │ ├── ProductForm.vue
│ │ │ ├── ProductItem.vue
│ │ │ └── ProductList.vue
│ ├── main.js
│ ├── pages
│ │ ├── Cart.vue
│ │ ├── Detail.vue
│ │ ├── Home.vue
│ │ ├── admin
│ │ │ ├── Edit.vue
│ │ │ ├── EditManufacturers.vue
│ │ │ ├── Index.vue
│ │ │ ├── Manufacturers.vue
│ │ │ ├── New.vue
│ │ │ ├── NewManufacturers.vue
│ │ │ └── Products.vue
│ │ └── user
│ │ │ ├── Index.vue
│ │ │ ├── Login.vue
│ │ │ └── Setting.vue
│ ├── router
│ │ └── index.js
│ └── store
│ │ ├── actions.js
│ │ ├── getters.js
│ │ ├── index.js
│ │ ├── mutation-types.js
│ │ └── mutations.js
├── static
│ └── .gitkeep
└── yarn.lock
├── docker-compose.yml
└── server
├── .dockerignore
├── .gitignore
├── Dockerfile
├── app.js
├── bin
└── www
├── controllers
├── manufacturer.js
└── product.js
├── data
├── manufacturers.json
└── products.json
├── model
└── index.js
├── package-lock.json
├── package.json
├── public
└── stylesheets
│ └── style.css
├── routes
├── api
│ └── index.js
├── index.js
└── users.js
├── views
├── error.ejs
└── index.ejs
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Tuture-related files
2 |
3 | .tuture
4 | tuture-error.log
5 |
6 | tuture-build/
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用
2 |
3 | 【已完成】这里是《从零到部署:用 Vue 和 Express 实现迷你全栈电商应用》系列教程的源代码仓库。
4 |
5 |
6 | ## 项目预览
7 |
8 | 
9 |
10 |
11 | ## 项目界面说明
12 |
13 |
14 | ### 首页
15 |
16 | 主要有首页头部导航栏以及展示本地商品信息的列表,列表主要展示了本地商品的名称、介绍、价格、生产商以及添加购物车操作。
17 |
18 | 
19 |
20 |
21 |
22 |
23 | ### 后台管理页面
24 |
25 | 主要用于对商品以及生产商的后台管理,包括查看商品(可以进行修改商品信息)、添加商品、查看生产商(可以进行修改生产商信息)以及添加生产商。
26 |
27 |
28 | #### 查看商品页面
29 |
30 | 主要展示了后台商品的名称、价格、制造商以及修改和删除操作。
31 |
32 | 
33 |
34 |
35 |
36 |
37 | #### 添加/修改商品页面
38 |
39 | 展示一个表单页面,主要用于添加一个新商品或者对指定商品信息进行修改。
40 |
41 | 
42 |
43 |
44 | #### 查看制造商页面
45 |
46 | 主要展示了后台制造商的名称以及修改和删除操作。
47 |
48 | 
49 |
50 |
51 | #### 添加/修改制造商页面
52 |
53 | 展示一个表单页面,主要用于添加一个新制造商或者对指定制造商信息进行修改。

54 |
55 |
56 | #### 购物车页面
57 |
58 | 主要用于展示添加到本地购物车的商品信息列表,列表主要展示了购物车商品的名称、介绍、价格、生产商以及移出购物车操作。

59 |
60 |
61 | ## 体验项目
62 |
63 |
64 |
65 | ### 克隆仓库,开启前端和后端服务服务:
66 |
67 | - 克隆仓库然后进入该仓库:
68 | ```bash
69 | git clone https://github.com/tuture-dev/vue-online-shop-frontend.git
70 | cd vue-online-shop-frontend
71 | ```
72 |
73 | ### 使用 Docker 一键开启服务
74 |
75 | 确保安装 Docker,然后执行如下命令:
76 |
77 | ```bash
78 | docker-compose up
79 | ```
80 |
81 | ### 手动开启服务
82 |
83 | #### 数据库
84 |
85 | 下载安装和启动 MongoDB:[https://www.mongodb.com/](https://www.mongodb.com/)
86 |
87 | ##### 前端:
88 |
89 | 在项目目录下:
90 |
91 | ```bash
92 | cd client
93 | npm install # yarn
94 | npm start # yarn start
95 | ```
96 |
97 | ##### 后端
98 |
99 | 在项目目录下:
100 |
101 | ```bash
102 | cd server
103 | npm install # yarn
104 | npm start # yarn start
105 | ```
106 |
107 |
108 | ## 教程内容概要
109 |
110 | 1. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(一)](https://tuture.co/2019/10/17/0b662ce/)
111 | 用 Vue 搭建前端项目的骨架,实现基于嵌套、动态路由的多页面跳转。
112 |
113 | 2. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(二)](https://tuture.co/2019/10/21/cb08dc8/)
114 | 我们通过基于 Node.js 平台的 Express 框架实现了后端 API 数据接口,并且将数据存储在 MongoDB 中。这样我们的网站就能够记录用户添加的商品,并且无论以后什么时候打开,都能获取我们之前的记录。
115 |
116 | 3. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(三)](https://tuture.co/2019/12/18/5e10a46/)
117 | 我们讲解了 Vue 实例的 Props 和 Methods,接着我们又讲解了最常见的 Vue 模板语法,并通过实例的方式将这些模板语法都实践了一番,最后我们讲解了 Vue 组件的组合,并完成了我们的发表商品页面。
118 |
119 | 4. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(四)](https://tuture.co/2020/01/10/ae8a389/)
120 | 我们使用了状态管理库 Vuex 并带大家熟悉了 Store、Mutation 和 Action 三大关键概念,然后升级了迷你商城应用的前端代码。
121 |
122 | 5. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(五)](https://tuture.co/2020/02/11/6f96d15/)
123 | 我们带大家抽出了 Vue 组件从而简化页面逻辑,使用 Vuex Getters 复用本地数据获取逻辑。
124 |
125 | 6. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(六)](https://tuture.co/2020/03/03/-Oixkkq/)
126 | 我们带大家一起学习了如何抽出 Getters 、 Mutations 和Actions 逻辑实现store的“减重”以及如何干掉 mutation-types 硬编码。
127 |
128 | 7. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(七)](https://tuture.co/2020/03/13/tc1c9oD/)
129 | 我们基于element-ui组件库重构了项目的前端代码,改善迷你电商应用的界面效果,提高用户的体验感;并且从试错的角度带大家一起踩了代码重构造成的一系列坑。
130 |
131 | 8. [ 从零到部署:用 Vue 和 Express 实现迷你全栈电商应用(八)](https://tuture.co/2020/03/14/-td0ssr/)
132 | 我们首先使用 Docker 来容器化应用,接着教大家配置了 MongoDB 的身份验证机制,给数据库添加一份安全守护,最后我们教大家使用阿里云的容器镜像服务将整个全栈应用部署到了云端,使互联网上的用户可以访问我们的网站。
133 |
134 | ## 反馈
135 |
136 | 欢迎对此教程的内容进行反馈(无论是疑问还是改进意见),可以在文章下方留言,也可以在此仓库创建 Issue!
137 |
138 |
139 | ### 联系我们
140 |
141 | - [微信公众号](https://tuture.co/images/social/wechat.png):关注公众号,加图雀酱微信拉你进学习交流群
142 | - [掘金](https://juejin.im/user/5b33414351882574b9694d28)
143 | - [知乎专栏](https://zhuanlan.zhihu.com/tuture)
144 | - 知乎圈子:搜索 图雀社区
145 | - 也可以直接扫码下方的二维码关注微信公众号哦:
146 | 
147 |
148 | ****
149 | ## 许可证
150 |
151 | MIT。
152 |
--------------------------------------------------------------------------------
/client/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"]
12 | }
13 |
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/client/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/client/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 |
--------------------------------------------------------------------------------
/client/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
13 | extends: ['plugin:vue/essential', 'airbnb-base'],
14 | // required to lint *.vue files
15 | plugins: [
16 | 'vue'
17 | ],
18 | // check if imports actually resolve
19 | settings: {
20 | 'import/resolver': {
21 | webpack: {
22 | config: 'build/webpack.base.conf.js'
23 | }
24 | }
25 | },
26 | // add your custom rules here
27 | rules: {
28 | // don't require .vue extension when importing
29 | 'import/extensions': ['error', 'always', {
30 | js: 'never',
31 | vue: 'never'
32 | }],
33 | // disallow reassignment of function parameters
34 | // disallow parameter object manipulation except for specific exclusions
35 | 'no-param-reassign': ['error', {
36 | props: true,
37 | ignorePropertyModificationsFor: [
38 | 'state', // for vuex state
39 | 'acc', // for reduce accumulators
40 | 'e' // for e.returnvalue
41 | ]
42 | }],
43 | // allow optionalDependencies
44 | 'import/no-extraneous-dependencies': ['error', {
45 | optionalDependencies: ['test/unit/index.js']
46 | }],
47 | // allow debugger during development
48 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/client/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.13
2 |
3 | # 删除 Nginx 的默认配置
4 | RUN rm /etc/nginx/conf.d/default.conf
5 |
6 | # 添加自定义 Nginx 配置
7 | COPY config/nginx.conf /etc/nginx/conf.d/
8 |
9 | # 将前端静态文件拷贝到容器的 /www 目录下
10 | COPY dist /www
11 |
--------------------------------------------------------------------------------
/client/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/client/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/build/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuture-dev/vue-online-shop-frontend/f25eb7cbe23d905594334ddeede9a1e13d2d8462/client/build/logo.png
--------------------------------------------------------------------------------
/client/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const packageConfig = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 |
12 | return path.posix.join(assetsSubDirectory, _path)
13 | }
14 |
15 | exports.cssLoaders = function (options) {
16 | options = options || {}
17 |
18 | const cssLoader = {
19 | loader: 'css-loader',
20 | options: {
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | const postcssLoader = {
26 | loader: 'postcss-loader',
27 | options: {
28 | sourceMap: options.sourceMap
29 | }
30 | }
31 |
32 | // generate loader string to be used with extract text plugin
33 | function generateLoaders (loader, loaderOptions) {
34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35 |
36 | if (loader) {
37 | loaders.push({
38 | loader: loader + '-loader',
39 | options: Object.assign({}, loaderOptions, {
40 | sourceMap: options.sourceMap
41 | })
42 | })
43 | }
44 |
45 | // Extract CSS when that option is specified
46 | // (which is the case during production build)
47 | if (options.extract) {
48 | return ExtractTextPlugin.extract({
49 | use: loaders,
50 | fallback: 'vue-style-loader'
51 | })
52 | } else {
53 | return ['vue-style-loader'].concat(loaders)
54 | }
55 | }
56 |
57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
58 | return {
59 | css: generateLoaders(),
60 | postcss: generateLoaders(),
61 | less: generateLoaders('less'),
62 | sass: generateLoaders('sass', { indentedSyntax: true }),
63 | scss: generateLoaders('sass'),
64 | stylus: generateLoaders('stylus'),
65 | styl: generateLoaders('stylus')
66 | }
67 | }
68 |
69 | // Generate loaders for standalone style files (outside of .vue)
70 | exports.styleLoaders = function (options) {
71 | const output = []
72 | const loaders = exports.cssLoaders(options)
73 |
74 | for (const extension in loaders) {
75 | const loader = loaders[extension]
76 | output.push({
77 | test: new RegExp('\\.' + extension + '$'),
78 | use: loader
79 | })
80 | }
81 |
82 | return output
83 | }
84 |
85 | exports.createNotifierCallback = () => {
86 | const notifier = require('node-notifier')
87 |
88 | return (severity, errors) => {
89 | if (severity !== 'error') return
90 |
91 | const error = errors[0]
92 | const filename = error.file && error.file.split('!').pop()
93 |
94 | notifier.notify({
95 | title: packageConfig.name,
96 | message: severity + ': ' + error.name,
97 | subtitle: filename || '',
98 | icon: path.join(__dirname, 'logo.png')
99 | })
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/client/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | }),
14 | cssSourceMap: sourceMapEnabled,
15 | cacheBusting: config.dev.cacheBusting,
16 | transformToRequire: {
17 | video: ['src', 'poster'],
18 | source: 'src',
19 | img: 'src',
20 | image: 'xlink:href'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | const path = require("path");
3 | const utils = require("./utils");
4 | const config = require("../config");
5 | const vueLoaderConfig = require("./vue-loader.conf");
6 |
7 | function resolve(dir) {
8 | return path.join(__dirname, "..", dir);
9 | }
10 |
11 | const createLintingRule = () => ({
12 | test: /\.(js|vue)$/,
13 | loader: "eslint-loader",
14 | enforce: "pre",
15 | include: [resolve("src"), resolve("test")],
16 | options: {
17 | formatter: require("eslint-friendly-formatter"),
18 | emitWarning: !config.dev.showEslintErrorsInOverlay
19 | }
20 | });
21 |
22 | module.exports = {
23 | context: path.resolve(__dirname, "../"),
24 | entry: {
25 | app: "./src/main.js"
26 | },
27 | output: {
28 | path: config.build.assetsRoot,
29 | filename: "[name].js",
30 | publicPath:
31 | process.env.NODE_ENV === "production"
32 | ? config.build.assetsPublicPath
33 | : config.dev.assetsPublicPath
34 | },
35 | resolve: {
36 | extensions: [".js", ".vue", ".json"],
37 | alias: {
38 | vue$: "vue/dist/vue.esm.js",
39 | "@": resolve("src")
40 | }
41 | },
42 | module: {
43 | rules: [
44 | {
45 | test: /\.vue$/,
46 | loader: "vue-loader",
47 | options: vueLoaderConfig
48 | },
49 | {
50 | test: /\.js$/,
51 | loader: "babel-loader",
52 | include: [
53 | resolve("src"),
54 | resolve("test"),
55 | resolve("node_modules/webpack-dev-server/client")
56 | ]
57 | },
58 | {
59 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
60 | loader: "url-loader",
61 | options: {
62 | limit: 10000,
63 | name: utils.assetsPath("img/[name].[hash:7].[ext]")
64 | }
65 | },
66 | {
67 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
68 | loader: "url-loader",
69 | options: {
70 | limit: 10000,
71 | name: utils.assetsPath("media/[name].[hash:7].[ext]")
72 | }
73 | },
74 | {
75 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
76 | loader: "url-loader",
77 | options: {
78 | limit: 10000,
79 | name: utils.assetsPath("fonts/[name].[hash:7].[ext]")
80 | }
81 | }
82 | ]
83 | },
84 | node: {
85 | // prevent webpack from injecting useless setImmediate polyfill because Vue
86 | // source contains it (although only uses it if it's native).
87 | setImmediate: false,
88 | // prevent webpack from injecting mocks to Node native modules
89 | // that does not make sense for the client
90 | dgram: "empty",
91 | fs: "empty",
92 | net: "empty",
93 | tls: "empty",
94 | child_process: "empty"
95 | }
96 | };
97 |
--------------------------------------------------------------------------------
/client/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
11 | const portfinder = require('portfinder')
12 |
13 | const HOST = process.env.HOST
14 | const PORT = process.env.PORT && Number(process.env.PORT)
15 |
16 | const devWebpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
19 | },
20 | // cheap-module-eval-source-map is faster for development
21 | devtool: config.dev.devtool,
22 |
23 | // these devServer options should be customized in /config/index.js
24 | devServer: {
25 | clientLogLevel: 'warning',
26 | historyApiFallback: {
27 | rewrites: [
28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
29 | ],
30 | },
31 | hot: true,
32 | contentBase: false, // since we use CopyWebpackPlugin.
33 | compress: true,
34 | host: HOST || config.dev.host,
35 | port: PORT || config.dev.port,
36 | open: config.dev.autoOpenBrowser,
37 | overlay: config.dev.errorOverlay
38 | ? { warnings: false, errors: true }
39 | : false,
40 | publicPath: config.dev.assetsPublicPath,
41 | proxy: config.dev.proxyTable,
42 | quiet: true, // necessary for FriendlyErrorsPlugin
43 | watchOptions: {
44 | poll: config.dev.poll,
45 | }
46 | },
47 | plugins: [
48 | new webpack.DefinePlugin({
49 | 'process.env': require('../config/dev.env')
50 | }),
51 | new webpack.HotModuleReplacementPlugin(),
52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
53 | new webpack.NoEmitOnErrorsPlugin(),
54 | // https://github.com/ampedandwired/html-webpack-plugin
55 | new HtmlWebpackPlugin({
56 | filename: 'index.html',
57 | template: 'index.html',
58 | inject: true
59 | }),
60 | // copy custom static assets
61 | new CopyWebpackPlugin([
62 | {
63 | from: path.resolve(__dirname, '../static'),
64 | to: config.dev.assetsSubDirectory,
65 | ignore: ['.*']
66 | }
67 | ])
68 | ]
69 | })
70 |
71 | module.exports = new Promise((resolve, reject) => {
72 | portfinder.basePort = process.env.PORT || config.dev.port
73 | portfinder.getPort((err, port) => {
74 | if (err) {
75 | reject(err)
76 | } else {
77 | // publish the new Port, necessary for e2e tests
78 | process.env.PORT = port
79 | // add port to devServer config
80 | devWebpackConfig.devServer.port = port
81 |
82 | // Add FriendlyErrorsPlugin
83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
84 | compilationSuccessInfo: {
85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
86 | },
87 | onErrors: config.dev.notifyOnErrors
88 | ? utils.createNotifierCallback()
89 | : undefined
90 | }))
91 |
92 | resolve(devWebpackConfig)
93 | }
94 | })
95 | })
96 |
--------------------------------------------------------------------------------
/client/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13 |
14 | const env = require('../config/prod.env')
15 |
16 | const webpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({
19 | sourceMap: config.build.productionSourceMap,
20 | extract: true,
21 | usePostCSS: true
22 | })
23 | },
24 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
25 | output: {
26 | path: config.build.assetsRoot,
27 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29 | },
30 | plugins: [
31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
32 | new webpack.DefinePlugin({
33 | 'process.env': env
34 | }),
35 | new UglifyJsPlugin({
36 | uglifyOptions: {
37 | compress: {
38 | warnings: false
39 | }
40 | },
41 | sourceMap: config.build.productionSourceMap,
42 | parallel: true
43 | }),
44 | // extract css into its own file
45 | new ExtractTextPlugin({
46 | filename: utils.assetsPath('css/[name].[contenthash].css'),
47 | // Setting the following option to `false` will not extract CSS from codesplit chunks.
48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
51 | allChunks: true,
52 | }),
53 | // Compress extracted CSS. We are using this plugin so that possible
54 | // duplicated CSS from different components can be deduped.
55 | new OptimizeCSSPlugin({
56 | cssProcessorOptions: config.build.productionSourceMap
57 | ? { safe: true, map: { inline: false } }
58 | : { safe: true }
59 | }),
60 | // generate dist index.html with correct asset hash for caching.
61 | // you can customize output by editing /index.html
62 | // see https://github.com/ampedandwired/html-webpack-plugin
63 | new HtmlWebpackPlugin({
64 | filename: config.build.index,
65 | template: 'index.html',
66 | inject: true,
67 | minify: {
68 | removeComments: true,
69 | collapseWhitespace: true,
70 | removeAttributeQuotes: true
71 | // more options:
72 | // https://github.com/kangax/html-minifier#options-quick-reference
73 | },
74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
75 | chunksSortMode: 'dependency'
76 | }),
77 | // keep module.id stable when vendor modules does not change
78 | new webpack.HashedModuleIdsPlugin(),
79 | // enable scope hoisting
80 | new webpack.optimize.ModuleConcatenationPlugin(),
81 | // split vendor js into its own file
82 | new webpack.optimize.CommonsChunkPlugin({
83 | name: 'vendor',
84 | minChunks (module) {
85 | // any required modules inside node_modules are extracted to vendor
86 | return (
87 | module.resource &&
88 | /\.js$/.test(module.resource) &&
89 | module.resource.indexOf(
90 | path.join(__dirname, '../node_modules')
91 | ) === 0
92 | )
93 | }
94 | }),
95 | // extract webpack runtime and module manifest to its own file in order to
96 | // prevent vendor hash from being updated whenever app bundle is updated
97 | new webpack.optimize.CommonsChunkPlugin({
98 | name: 'manifest',
99 | minChunks: Infinity
100 | }),
101 | // This instance extracts shared chunks from code splitted chunks and bundles them
102 | // in a separate chunk, similar to the vendor chunk
103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
104 | new webpack.optimize.CommonsChunkPlugin({
105 | name: 'app',
106 | async: 'vendor-async',
107 | children: true,
108 | minChunks: 3
109 | }),
110 |
111 | // copy custom static assets
112 | new CopyWebpackPlugin([
113 | {
114 | from: path.resolve(__dirname, '../static'),
115 | to: config.build.assetsSubDirectory,
116 | ignore: ['.*']
117 | }
118 | ])
119 | ]
120 | })
121 |
122 | if (config.build.productionGzip) {
123 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
124 |
125 | webpackConfig.plugins.push(
126 | new CompressionWebpackPlugin({
127 | asset: '[path].gz[query]',
128 | algorithm: 'gzip',
129 | test: new RegExp(
130 | '\\.(' +
131 | config.build.productionGzipExtensions.join('|') +
132 | ')$'
133 | ),
134 | threshold: 10240,
135 | minRatio: 0.8
136 | })
137 | )
138 | }
139 |
140 | if (config.build.bundleAnalyzerReport) {
141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
143 | }
144 |
145 | module.exports = webpackConfig
146 |
--------------------------------------------------------------------------------
/client/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/client/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {},
14 |
15 | // Various Dev Server settings
16 | host: 'localhost', // can be overwritten by process.env.HOST
17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
18 | autoOpenBrowser: false,
19 | errorOverlay: true,
20 | notifyOnErrors: true,
21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
22 |
23 | // Use Eslint Loader?
24 | // If true, your code will be linted during bundling and
25 | // linting errors and warnings will be shown in the console.
26 | useEslint: true,
27 | // If true, eslint errors and warnings will also be shown in the error overlay
28 | // in the browser.
29 | showEslintErrorsInOverlay: false,
30 |
31 | /**
32 | * Source Maps
33 | */
34 |
35 | // https://webpack.js.org/configuration/devtool/#development
36 | devtool: 'cheap-module-eval-source-map',
37 |
38 | // If you have problems debugging vue-files in devtools,
39 | // set this to false - it *may* help
40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
41 | cacheBusting: true,
42 |
43 | cssSourceMap: true
44 | },
45 |
46 | build: {
47 | // Template for index.html
48 | index: path.resolve(__dirname, '../dist/index.html'),
49 |
50 | // Paths
51 | assetsRoot: path.resolve(__dirname, '../dist'),
52 | assetsSubDirectory: 'static',
53 | assetsPublicPath: '/',
54 |
55 | /**
56 | * Source Maps
57 | */
58 |
59 | productionSourceMap: true,
60 | // https://webpack.js.org/configuration/devtool/#production
61 | devtool: '#source-map',
62 |
63 | // Gzip off by default as many popular static hosts such as
64 | // Surge or Netlify already gzip all static assets for you.
65 | // Before setting to `true`, make sure to:
66 | // npm install --save-dev compression-webpack-plugin
67 | productionGzip: false,
68 | productionGzipExtensions: ['js', 'css'],
69 |
70 | // Run the build command with an extra argument to
71 | // View the bundle analyzer report after build finishes:
72 | // `npm run build --report`
73 | // Set to `true` or `false` to always turn it on or off
74 | bundleAnalyzerReport: process.env.npm_config_report
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/client/config/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | root /www;
4 | index index.html;
5 | sendfile on;
6 | sendfile_max_chunk 1M;
7 | tcp_nopush on;
8 | gzip_static on;
9 |
10 | location /api/v1 {
11 | proxy_pass http://api:3000;
12 | }
13 |
14 | location / {
15 | try_files $uri $uri/ /index.html;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 | {{product.description}} 12 |
13 |{{product.price}}
16 |<%= error.stack %>4 | -------------------------------------------------------------------------------- /server/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
Welcome to <%= title %>
10 | 11 | 12 | -------------------------------------------------------------------------------- /server/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.3: 6 | version "1.3.7" 7 | resolved "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 8 | integrity sha1-UxvHJlF6OytB+FACHGzBXqq1B80= 9 | dependencies: 10 | mime-types "~2.1.24" 11 | negotiator "0.6.2" 12 | 13 | array-flatten@1.1.1: 14 | version "1.1.1" 15 | resolved "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz?cache=0&sync_timestamp=1574313315299&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-flatten%2Fdownload%2Farray-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 16 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 17 | 18 | basic-auth@~2.0.0: 19 | version "2.0.1" 20 | resolved "https://registry.npm.taobao.org/basic-auth/download/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" 21 | integrity sha1-uZgnm/R844NEtPPPkW1Gebv1Hjo= 22 | dependencies: 23 | safe-buffer "5.1.2" 24 | 25 | bl@^2.2.0: 26 | version "2.2.0" 27 | resolved "https://registry.npm.taobao.org/bl/download/bl-2.2.0.tgz?cache=0&sync_timestamp=1583337750539&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbl%2Fdownload%2Fbl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493" 28 | integrity sha1-4aV0zfUo5AUwGbuACwQcCsiNpJM= 29 | dependencies: 30 | readable-stream "^2.3.5" 31 | safe-buffer "^5.1.1" 32 | 33 | bluebird@3.5.1: 34 | version "3.5.1" 35 | resolved "https://registry.npm.taobao.org/bluebird/download/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 36 | integrity sha1-2VUfnemPH82h5oPRfukaBgLuLrk= 37 | 38 | body-parser@~1.18.2: 39 | version "1.18.3" 40 | resolved "https://registry.npm.taobao.org/body-parser/download/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 41 | integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= 42 | dependencies: 43 | bytes "3.0.0" 44 | content-type "~1.0.4" 45 | debug "2.6.9" 46 | depd "~1.1.2" 47 | http-errors "~1.6.3" 48 | iconv-lite "0.4.23" 49 | on-finished "~2.3.0" 50 | qs "6.5.2" 51 | raw-body "2.3.3" 52 | type-is "~1.6.16" 53 | 54 | bson@^1.1.1, bson@~1.1.1: 55 | version "1.1.3" 56 | resolved "https://registry.npm.taobao.org/bson/download/bson-1.1.3.tgz?cache=0&sync_timestamp=1578577060818&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbson%2Fdownload%2Fbson-1.1.3.tgz#aa82cb91f9a453aaa060d6209d0675114a8154d3" 57 | integrity sha1-qoLLkfmkU6qgYNYgnQZ1EUqBVNM= 58 | 59 | bytes@3.0.0: 60 | version "3.0.0" 61 | resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 62 | integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= 63 | 64 | content-disposition@0.5.2: 65 | version "0.5.2" 66 | resolved "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 67 | integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= 68 | 69 | content-type@~1.0.2, content-type@~1.0.4: 70 | version "1.0.4" 71 | resolved "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 72 | integrity sha1-4TjMdeBAxyexlm/l5fjJruJW/js= 73 | 74 | cookie-parser@~1.4.3: 75 | version "1.4.4" 76 | resolved "https://registry.npm.taobao.org/cookie-parser/download/cookie-parser-1.4.4.tgz#e6363de4ea98c3def9697b93421c09f30cf5d188" 77 | integrity sha1-5jY95OqYw975aXuTQhwJ8wz10Yg= 78 | dependencies: 79 | cookie "0.3.1" 80 | cookie-signature "1.0.6" 81 | 82 | cookie-signature@1.0.6: 83 | version "1.0.6" 84 | resolved "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 85 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 86 | 87 | cookie@0.3.1: 88 | version "0.3.1" 89 | resolved "https://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 90 | integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= 91 | 92 | core-util-is@~1.0.0: 93 | version "1.0.2" 94 | resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 95 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 96 | 97 | debug@2.6.9, debug@~2.6.9: 98 | version "2.6.9" 99 | resolved "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 100 | integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8= 101 | dependencies: 102 | ms "2.0.0" 103 | 104 | debug@3.1.0: 105 | version "3.1.0" 106 | resolved "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 107 | integrity sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE= 108 | dependencies: 109 | ms "2.0.0" 110 | 111 | denque@^1.4.1: 112 | version "1.4.1" 113 | resolved "https://registry.npm.taobao.org/denque/download/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" 114 | integrity sha1-Z0T/dkHBSMP4ppwwflEjXB9KN88= 115 | 116 | depd@~1.1.1, depd@~1.1.2: 117 | version "1.1.2" 118 | resolved "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 119 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 120 | 121 | destroy@~1.0.4: 122 | version "1.0.4" 123 | resolved "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 124 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 125 | 126 | ee-first@1.1.1: 127 | version "1.1.1" 128 | resolved "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 129 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 130 | 131 | ejs@~2.5.7: 132 | version "2.5.9" 133 | resolved "https://registry.npm.taobao.org/ejs/download/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" 134 | integrity sha1-e6JUWCpWDSZ0NxCaaDVBEkdbDOU= 135 | 136 | encodeurl@~1.0.1: 137 | version "1.0.2" 138 | resolved "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 139 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 140 | 141 | escape-html@~1.0.3: 142 | version "1.0.3" 143 | resolved "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 144 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 145 | 146 | etag@~1.8.0, etag@~1.8.1: 147 | version "1.8.1" 148 | resolved "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 149 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 150 | 151 | express@~4.15.5: 152 | version "4.15.5" 153 | resolved "https://registry.npm.taobao.org/express/download/express-4.15.5.tgz#670235ca9598890a5ae8170b83db722b842ed927" 154 | integrity sha1-ZwI1ypWYiQpa6BcLg9tyK4Qu2Sc= 155 | dependencies: 156 | accepts "~1.3.3" 157 | array-flatten "1.1.1" 158 | content-disposition "0.5.2" 159 | content-type "~1.0.2" 160 | cookie "0.3.1" 161 | cookie-signature "1.0.6" 162 | debug "2.6.9" 163 | depd "~1.1.1" 164 | encodeurl "~1.0.1" 165 | escape-html "~1.0.3" 166 | etag "~1.8.0" 167 | finalhandler "~1.0.6" 168 | fresh "0.5.2" 169 | merge-descriptors "1.0.1" 170 | methods "~1.1.2" 171 | on-finished "~2.3.0" 172 | parseurl "~1.3.1" 173 | path-to-regexp "0.1.7" 174 | proxy-addr "~1.1.5" 175 | qs "6.5.0" 176 | range-parser "~1.2.0" 177 | send "0.15.6" 178 | serve-static "1.12.6" 179 | setprototypeof "1.0.3" 180 | statuses "~1.3.1" 181 | type-is "~1.6.15" 182 | utils-merge "1.0.0" 183 | vary "~1.1.1" 184 | 185 | finalhandler@~1.0.6: 186 | version "1.0.6" 187 | resolved "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.0.6.tgz#007aea33d1a4d3e42017f624848ad58d212f814f" 188 | integrity sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8= 189 | dependencies: 190 | debug "2.6.9" 191 | encodeurl "~1.0.1" 192 | escape-html "~1.0.3" 193 | on-finished "~2.3.0" 194 | parseurl "~1.3.2" 195 | statuses "~1.3.1" 196 | unpipe "~1.0.0" 197 | 198 | forwarded@~0.1.0: 199 | version "0.1.2" 200 | resolved "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 201 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 202 | 203 | fresh@0.5.2: 204 | version "0.5.2" 205 | resolved "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 206 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 207 | 208 | http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: 209 | version "1.6.3" 210 | resolved "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 211 | integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= 212 | dependencies: 213 | depd "~1.1.2" 214 | inherits "2.0.3" 215 | setprototypeof "1.1.0" 216 | statuses ">= 1.4.0 < 2" 217 | 218 | iconv-lite@0.4.23: 219 | version "0.4.23" 220 | resolved "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz?cache=0&sync_timestamp=1579333981154&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 221 | integrity sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM= 222 | dependencies: 223 | safer-buffer ">= 2.1.2 < 3" 224 | 225 | inherits@2.0.3: 226 | version "2.0.3" 227 | resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 228 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 229 | 230 | inherits@~2.0.3: 231 | version "2.0.4" 232 | resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 233 | integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= 234 | 235 | ipaddr.js@1.4.0: 236 | version "1.4.0" 237 | resolved "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" 238 | integrity sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA= 239 | 240 | isarray@~1.0.0: 241 | version "1.0.0" 242 | resolved "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 243 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 244 | 245 | kareem@2.3.1: 246 | version "2.3.1" 247 | resolved "https://registry.npm.taobao.org/kareem/download/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" 248 | integrity sha1-3vEtnJQQF/q/sA+HOvlenJnhvoc= 249 | 250 | media-typer@0.3.0: 251 | version "0.3.0" 252 | resolved "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 253 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 254 | 255 | memory-pager@^1.0.2: 256 | version "1.5.0" 257 | resolved "https://registry.npm.taobao.org/memory-pager/download/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 258 | integrity sha1-2HUWVdItOEaCdByXLyw9bfo+ZrU= 259 | 260 | merge-descriptors@1.0.1: 261 | version "1.0.1" 262 | resolved "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 263 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 264 | 265 | methods@~1.1.2: 266 | version "1.1.2" 267 | resolved "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 268 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 269 | 270 | mime-db@1.43.0: 271 | version "1.43.0" 272 | resolved "https://registry.npm.taobao.org/mime-db/download/mime-db-1.43.0.tgz?cache=0&sync_timestamp=1578281193492&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" 273 | integrity sha1-ChLgUCZQ5HPXNVNQUOfI9OtPrlg= 274 | 275 | mime-types@~2.1.24: 276 | version "2.1.26" 277 | resolved "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.26.tgz?cache=0&sync_timestamp=1578282566609&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" 278 | integrity sha1-nJIfwJt+FJpl39wNpNIJlyALCgY= 279 | dependencies: 280 | mime-db "1.43.0" 281 | 282 | mime@1.3.4: 283 | version "1.3.4" 284 | resolved "https://registry.npm.taobao.org/mime/download/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 285 | integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= 286 | 287 | mongodb@3.5.4: 288 | version "3.5.4" 289 | resolved "https://registry.npm.taobao.org/mongodb/download/mongodb-3.5.4.tgz#f7609cfa9f8c56c35e844b4216ddc3a1b1ec5bef" 290 | integrity sha1-92Cc+p+MVsNehEtCFt3DobHsW+8= 291 | dependencies: 292 | bl "^2.2.0" 293 | bson "^1.1.1" 294 | denque "^1.4.1" 295 | require_optional "^1.0.1" 296 | safe-buffer "^5.1.2" 297 | optionalDependencies: 298 | saslprep "^1.0.0" 299 | 300 | mongoose-legacy-pluralize@1.0.2: 301 | version "1.0.2" 302 | resolved "https://registry.npm.taobao.org/mongoose-legacy-pluralize/download/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" 303 | integrity sha1-O6n5H6UHtRhtOZ+0CFS/8Y+1Y+Q= 304 | 305 | mongoose@^5.7.5: 306 | version "5.9.4" 307 | resolved "https://registry.npm.taobao.org/mongoose/download/mongoose-5.9.4.tgz#e80a58fdb066b815b1e87c2daf389f9fbb516f49" 308 | integrity sha1-6ApY/bBmuBWx6Hwtrzifn7tRb0k= 309 | dependencies: 310 | bson "~1.1.1" 311 | kareem "2.3.1" 312 | mongodb "3.5.4" 313 | mongoose-legacy-pluralize "1.0.2" 314 | mpath "0.6.0" 315 | mquery "3.2.2" 316 | ms "2.1.2" 317 | regexp-clone "1.0.0" 318 | safe-buffer "5.1.2" 319 | sift "7.0.1" 320 | sliced "1.0.1" 321 | 322 | morgan@~1.9.0: 323 | version "1.9.1" 324 | resolved "https://registry.npm.taobao.org/morgan/download/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" 325 | integrity sha1-Co0Wc0odmvvIJLmd+H5zjlji2lk= 326 | dependencies: 327 | basic-auth "~2.0.0" 328 | debug "2.6.9" 329 | depd "~1.1.2" 330 | on-finished "~2.3.0" 331 | on-headers "~1.0.1" 332 | 333 | mpath@0.6.0: 334 | version "0.6.0" 335 | resolved "https://registry.npm.taobao.org/mpath/download/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e" 336 | integrity sha1-qpIgKfyk8PZB82DnTFwbakxHB44= 337 | 338 | mquery@3.2.2: 339 | version "3.2.2" 340 | resolved "https://registry.npm.taobao.org/mquery/download/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" 341 | integrity sha1-4Tg6OVGFLOI+N/YZqbNQ8fs2ZOc= 342 | dependencies: 343 | bluebird "3.5.1" 344 | debug "3.1.0" 345 | regexp-clone "^1.0.0" 346 | safe-buffer "5.1.2" 347 | sliced "1.0.1" 348 | 349 | ms@2.0.0: 350 | version "2.0.0" 351 | resolved "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 352 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 353 | 354 | ms@2.1.2: 355 | version "2.1.2" 356 | resolved "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 357 | integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= 358 | 359 | negotiator@0.6.2: 360 | version "0.6.2" 361 | resolved "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 362 | integrity sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs= 363 | 364 | on-finished@~2.3.0: 365 | version "2.3.0" 366 | resolved "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 367 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 368 | dependencies: 369 | ee-first "1.1.1" 370 | 371 | on-headers@~1.0.1: 372 | version "1.0.2" 373 | resolved "https://registry.npm.taobao.org/on-headers/download/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" 374 | integrity sha1-dysK5qqlJcOZ5Imt+tkMQD6zwo8= 375 | 376 | parseurl@~1.3.1, parseurl@~1.3.2: 377 | version "1.3.3" 378 | resolved "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 379 | integrity sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ= 380 | 381 | path-to-regexp@0.1.7: 382 | version "0.1.7" 383 | resolved "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 384 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 385 | 386 | process-nextick-args@~2.0.0: 387 | version "2.0.1" 388 | resolved "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 389 | integrity sha1-eCDZsWEgzFXKmud5JoCufbptf+I= 390 | 391 | proxy-addr@~1.1.5: 392 | version "1.1.5" 393 | resolved "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-1.1.5.tgz?cache=0&sync_timestamp=1582556112011&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fproxy-addr%2Fdownload%2Fproxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" 394 | integrity sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg= 395 | dependencies: 396 | forwarded "~0.1.0" 397 | ipaddr.js "1.4.0" 398 | 399 | qs@6.5.0: 400 | version "6.5.0" 401 | resolved "https://registry.npm.taobao.org/qs/download/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" 402 | integrity sha1-jQSVTTZN7z78VbWgeT4eLIsebkk= 403 | 404 | qs@6.5.2: 405 | version "6.5.2" 406 | resolved "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 407 | integrity sha1-yzroBuh0BERYTvFUzo7pjUA/PjY= 408 | 409 | range-parser@~1.2.0: 410 | version "1.2.1" 411 | resolved "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 412 | integrity sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE= 413 | 414 | raw-body@2.3.3: 415 | version "2.3.3" 416 | resolved "https://registry.npm.taobao.org/raw-body/download/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 417 | integrity sha1-GzJOzmtXBuFThVvBFIxlu39uoMM= 418 | dependencies: 419 | bytes "3.0.0" 420 | http-errors "1.6.3" 421 | iconv-lite "0.4.23" 422 | unpipe "1.0.0" 423 | 424 | readable-stream@^2.3.5: 425 | version "2.3.7" 426 | resolved "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz?cache=0&sync_timestamp=1581622984924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 427 | integrity sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c= 428 | dependencies: 429 | core-util-is "~1.0.0" 430 | inherits "~2.0.3" 431 | isarray "~1.0.0" 432 | process-nextick-args "~2.0.0" 433 | safe-buffer "~5.1.1" 434 | string_decoder "~1.1.1" 435 | util-deprecate "~1.0.1" 436 | 437 | regexp-clone@1.0.0, regexp-clone@^1.0.0: 438 | version "1.0.0" 439 | resolved "https://registry.npm.taobao.org/regexp-clone/download/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" 440 | integrity sha1-Ii25Z2IydwViYLmSYmNUoEzpv2M= 441 | 442 | require_optional@^1.0.1: 443 | version "1.0.1" 444 | resolved "https://registry.npm.taobao.org/require_optional/download/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" 445 | integrity sha1-TPNaQkf2TKPfjC7yCMxJSxyo/C4= 446 | dependencies: 447 | resolve-from "^2.0.0" 448 | semver "^5.1.0" 449 | 450 | resolve-from@^2.0.0: 451 | version "2.0.0" 452 | resolved "https://registry.npm.taobao.org/resolve-from/download/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" 453 | integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= 454 | 455 | safe-buffer@5.1.1: 456 | version "5.1.1" 457 | resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 458 | integrity sha1-iTMSr2myEj3vcfV4iQAWce6yyFM= 459 | 460 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 461 | version "5.1.2" 462 | resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 463 | integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= 464 | 465 | safe-buffer@^5.1.1, safe-buffer@^5.1.2: 466 | version "5.2.0" 467 | resolved "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" 468 | integrity sha1-t02uxJsRSPiMZLaNSbHoFcHy9Rk= 469 | 470 | "safer-buffer@>= 2.1.2 < 3": 471 | version "2.1.2" 472 | resolved "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 473 | integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo= 474 | 475 | saslprep@^1.0.0: 476 | version "1.0.3" 477 | resolved "https://registry.npm.taobao.org/saslprep/download/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" 478 | integrity sha1-TAL5RrVs9UKX40e6EJPnrKxM8iY= 479 | dependencies: 480 | sparse-bitfield "^3.0.3" 481 | 482 | semver@^5.1.0: 483 | version "5.7.1" 484 | resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 485 | integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= 486 | 487 | send@0.15.6: 488 | version "0.15.6" 489 | resolved "https://registry.npm.taobao.org/send/download/send-0.15.6.tgz#20f23a9c925b762ab82705fe2f9db252ace47e34" 490 | integrity sha1-IPI6nJJbdiq4JwX+L52yUqzkfjQ= 491 | dependencies: 492 | debug "2.6.9" 493 | depd "~1.1.1" 494 | destroy "~1.0.4" 495 | encodeurl "~1.0.1" 496 | escape-html "~1.0.3" 497 | etag "~1.8.1" 498 | fresh "0.5.2" 499 | http-errors "~1.6.2" 500 | mime "1.3.4" 501 | ms "2.0.0" 502 | on-finished "~2.3.0" 503 | range-parser "~1.2.0" 504 | statuses "~1.3.1" 505 | 506 | serve-favicon@~2.4.5: 507 | version "2.4.5" 508 | resolved "https://registry.npm.taobao.org/serve-favicon/download/serve-favicon-2.4.5.tgz#49d9a46863153a9240691c893d2b0e7d85d6d436" 509 | integrity sha1-SdmkaGMVOpJAaRyJPSsOfYXW1DY= 510 | dependencies: 511 | etag "~1.8.1" 512 | fresh "0.5.2" 513 | ms "2.0.0" 514 | parseurl "~1.3.2" 515 | safe-buffer "5.1.1" 516 | 517 | serve-static@1.12.6: 518 | version "1.12.6" 519 | resolved "https://registry.npm.taobao.org/serve-static/download/serve-static-1.12.6.tgz#b973773f63449934da54e5beba5e31d9f4211577" 520 | integrity sha1-uXN3P2NEmTTaVOW+ul4x2fQhFXc= 521 | dependencies: 522 | encodeurl "~1.0.1" 523 | escape-html "~1.0.3" 524 | parseurl "~1.3.2" 525 | send "0.15.6" 526 | 527 | setprototypeof@1.0.3: 528 | version "1.0.3" 529 | resolved "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 530 | integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= 531 | 532 | setprototypeof@1.1.0: 533 | version "1.1.0" 534 | resolved "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 535 | integrity sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY= 536 | 537 | sift@7.0.1: 538 | version "7.0.1" 539 | resolved "https://registry.npm.taobao.org/sift/download/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" 540 | integrity sha1-R9YsULFZ0xbxNy+LU/nBDNIaSwg= 541 | 542 | sliced@1.0.1: 543 | version "1.0.1" 544 | resolved "https://registry.npm.taobao.org/sliced/download/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" 545 | integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= 546 | 547 | sparse-bitfield@^3.0.3: 548 | version "3.0.3" 549 | resolved "https://registry.npm.taobao.org/sparse-bitfield/download/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 550 | integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= 551 | dependencies: 552 | memory-pager "^1.0.2" 553 | 554 | "statuses@>= 1.4.0 < 2": 555 | version "1.5.0" 556 | resolved "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 557 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 558 | 559 | statuses@~1.3.1: 560 | version "1.3.1" 561 | resolved "https://registry.npm.taobao.org/statuses/download/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 562 | integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= 563 | 564 | string_decoder@~1.1.1: 565 | version "1.1.1" 566 | resolved "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 567 | integrity sha1-nPFhG6YmhdcDCunkujQUnDrwP8g= 568 | dependencies: 569 | safe-buffer "~5.1.0" 570 | 571 | type-is@~1.6.15, type-is@~1.6.16: 572 | version "1.6.18" 573 | resolved "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 574 | integrity sha1-TlUs0F3wlGfcvE73Od6J8s83wTE= 575 | dependencies: 576 | media-typer "0.3.0" 577 | mime-types "~2.1.24" 578 | 579 | unpipe@1.0.0, unpipe@~1.0.0: 580 | version "1.0.0" 581 | resolved "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 582 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 583 | 584 | util-deprecate@~1.0.1: 585 | version "1.0.2" 586 | resolved "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 587 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 588 | 589 | utils-merge@1.0.0: 590 | version "1.0.0" 591 | resolved "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 592 | integrity sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg= 593 | 594 | vary@~1.1.1: 595 | version "1.1.2" 596 | resolved "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 597 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 598 | --------------------------------------------------------------------------------