Ver código fonte

增加UML组件库

shaun-sheep 4 anos atrás
commit
14a3b05240

+ 119 - 0
persagy-vue-doc/README.md

@@ -0,0 +1,119 @@
+# sybotan-vue-doc
+
+sybotan-vue-doc 项目提供在 vuepress 文档上引入 git 源代码功能。目前只支持基于 gogs 的 git 仓库。 
+
+## 安装
+
+修改项目文件 “package.json”。在 “dependencies” 项目下增加 "sybotan-vue-doc"依赖。
+
+``` javascript
+  "dependencies": {
+
+    ......
+
+    "sybotan-vue-doc": "^1.1.21",
+
+    ......
+
+  },
+```
+
+* 注:版本不定时更新,版本号请根据发布的最新版本修改。
+
+在 Windows 控制台 或 IDE 开发环境的控制台窗口,切换到文档项目所在文件夹。执行以下安装命令。
+
+``` shell
+npm install
+```
+
+## 引入组件
+修改项目文件 “docs/.vuepress/enhanceApp.js“,如果不存在则创建该文件。
+
+``` javascript
+import Vue from "vue"
+import SDoc from "sybotan-vue-doc"
+Vue.use(SDoc);
+```
+
+## PCodeGit 组件
+PCodeGit 组件用于在文档中引入 git 代码。例如,以下代码引用 git 仓库 ”libs/sybotan-ts“ 的代码 ”/base/src/core/SObject.ts“。
+
+``` html 
+<PCodeGit repos="libs/sybotan-ts" src="/base/src/core/SObject.ts" lang="javascript"></PCodeGit>
+```
+
+### 属性
+
+| 属性 | 说明 | 默认值 | 必须 |
+|:---:|---|:---:|:---:|
+| repos | git 仓库名称 | - | 是 |
+| src | 源码路径 | - | 是 |
+| branch | 分枝 | master | - |
+| lang | 语言 | javascript | - |
+
+* 组件访问的 git 地下:"/gogs/" + repos + "/raw/" + branch + src
+* 如果读取的分枝不是主分析时,需要指定 branch 属性;
+* lang 支持的语言有: javascript, css, html, xml, java, kotlin, c, c++, C#, python, kotlin 等等。
+
+### 配置代理
+git 仓库与文档可能不在一个服务器上,这将导至跨域访问问题。因此,需要配置代理来解决跨域问题。
+
+#### 开发环境配置
+修改 vuepress 项目的项目配置文件 “docs/.vuepress/config.js”。在 module.exports 配置中增加 git 代理设置。
+
+``` javascript
+module.exports = {
+
+    ......
+
+    devServer: {
+        proxy: {
+            '/gogs/': {
+                target: 'http://git.sybotan.com',
+                ws: true,
+                changeOrigin: true,
+                pathRewrite: {
+                    '^/gogs/': '/'
+                },
+                bypass: function(req, res, proxyOptions) {
+                    req.headers["Authorization"] = "Basic Z29nczoxMjM0NTY="
+                }
+            }
+        }
+    }
+}
+```
+
+说明:
+* /gogs/ 代理:如果前缀为 ”/gogs/“ ,则执行代理;
+* target: 设置 "/gogs/" 前缀被转向的目标地址;
+* changeOrigin: 是否支持跨域;
+* pathRewrite: 代理到目标地址后,url 的变更。该例为将 ”/gogs/“ 前缀变更为 ”/“。
+* bypass: 在发出代理请求时执行的动作。示例中是在发出 git 源理请求时,在请求头中加入认证信息。
+* 认证信息后的串为 git 请求的用户名与用户密码。格式为: ”<用户名>:<用户密码>“ 。例如,”gogs:123456“。经过 Base64 加密码后即为上述字符串。
+
+#### nginx 服务器配置
+nginx 的配置文件在 ”/etc/nginx/conf.d/“ 文件夹下。以下示例为文档放在 http://docs.sybotan.com ,gogs 仓库部署在 http://git.sybotan.com 的示例配置。
+
+```
+server {
+    listen         80;
+    server_name    docs.sybotan.com;
+
+    location / {
+        root   /web/docs;
+        index  index.html index.htm;
+    }
+    location /gogs {
+        proxy_pass http://git.sybotan.com;
+        proxy_set_header Authorization "Basic Z29nczoxMjM0NTY=";
+        rewrite  ^/gogs/(.*)$ /$1 break;
+    }
+}
+```
+说明:
+* ”location /gogs“ :该段配置 nginx 的代理。关于 nginx 代理更详细信息请自行在网络上查找相关说明;
+* proxy_pass: 设置 "/gogs/" 前缀被转向的目标地址;
+* proxy_set_header:在发出代理请求时执行时在请求头中加入认证信息。
+* rewrite: 代理到目标地址后,url 的变更。该例为将 ”/gogs/“ 前缀变更为 ”/“。
+

+ 5 - 0
persagy-vue-doc/babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 12331 - 0
persagy-vue-doc/package-lock.json


+ 64 - 0
persagy-vue-doc/package-vue.json

@@ -0,0 +1,64 @@
+{
+  "name": "sybotan-vue-doc",
+  "version": "1.1.26",
+  "description": "Sybotan vuepress 文档扩展组件",
+  "private": false,
+  "author": "庞利祥  <sybotan@126.com>",
+  "license": "MIT",
+  "keywords": [
+    "sybotan",
+    "vue",
+    "vuepress",
+    "doc",
+    "git",
+    "database"
+  ],
+  "main": "lib/sybotan-vue-doc.umd.min.js",
+  "scripts": {
+    "build": "vue-cli-service build --target lib --name sybotan-vue-doc --dest lib src/index.js",
+    "build:lib": "cross-env NODE_ENV=production webpack --mode production --profile --progress --config webpack.components.config.js",
+    "publish": "npm publish",
+    "lint": "vue-cli-service lint"
+  },
+  "files": [
+    "lib"
+  ],
+  "publishConfig": {
+    "registry": "http://repos.sybotan.com:88/repository/npm-hosted/"
+  },
+  "dependencies": {
+    "axios": "^0.20.0",
+    "core-js": "^3.6.5",
+    "prismjs": "^1.21.0",
+    "vue": "^2.6.11"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "babel-eslint": "^10.1.0",
+
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

+ 65 - 0
persagy-vue-doc/package.json

@@ -0,0 +1,65 @@
+{
+  "name": "@persagy-vue/doc",
+  "version": "1.1.35",
+  "description": "persagy vue vuepress 文档扩展组件",
+  "private": false,
+  "author": "郝洁 <haojie@persagy.com.cn>",
+  "license": "persagy",
+  "keywords": [
+    "persagy",
+    "vue",
+    "vuepress",
+    "doc",
+    "git",
+    "database"
+  ],
+  "main": "lib/index.js",
+  "scripts": {
+    "build": "cross-env NODE_ENV=production webpack --mode production --profile --progress --config webpack.components.config.js",
+    "publish": "npm publish",
+    "lint": "vue-cli-service lint"
+  },
+  "files": [
+    "lib"
+  ],
+  "publishConfig": {
+    "registry": "http://dev.dp.sagacloud.cn:8082/repository/npm-hosted/"
+  },
+  "dependencies": {
+    "axios": "^0.20.0",
+    "core-js": "^3.6.5",
+    "prismjs": "^1.21.0",
+    "vue": "^2.6.11"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "babel-eslint": "^10.1.0",
+    "cross-env": "^7.0.2",
+    "eslint": "^6.7.2",
+    "eslint-plugin-vue": "^6.2.2",
+    "vue-loader": "^15.9.3",
+    "vue-template-compiler": "^2.6.11",
+    "webpack-cli": "^3.3.12"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ]
+}

+ 62 - 0
persagy-vue-doc/src/PCodeGit/PCodeGit.vue

@@ -0,0 +1,62 @@
+<template>
+    <details class="custom-block details">
+        <summary>查看代码:{{ src }}</summary>
+        <div :class="'line-numbers-mode language-'+lang">
+            <pre :class="'language-'+lang"><code :class="lang" v-html="code"></code></pre>
+            <div class="line-numbers-wrapper">
+                <template v-for="n in lineCount">
+                    <span class="line-number" :key="src + ':' + n">{{ n }}</span><br :key="src + '_' +n">
+                </template>
+            </div>
+        </div>
+    </details>
+</template>
+
+<script>
+import Axios from "axios"
+import Prism from "prismjs/prism"
+
+export default {
+    name: "PCodeGit",
+    data: function(){
+        return {
+            code: "",
+            lineCount: 1
+        };
+    },
+    props: {
+        repos: {
+            type: String,
+            required: true
+        },
+        src: {
+            type: String,
+            required: true
+        },
+        branch: {
+            type: String,
+            default: "master"
+        },
+        lang: {
+            type: String,
+            default: "javascript"
+        }
+    },
+    created() {
+        Axios({
+            method: "get",
+            url: `/gogs/${this.repos}/raw/${this.branch}${this.src}`,
+        }).then(res => {
+            this.Prism = Prism;
+            this.code = this.Prism.highlight(
+                res.data,           //想要高亮的内容
+                this.Prism.languages[this.lang],
+                this.lang
+            );
+
+            const lines = res.data.split(/\r\n|\r|\n/);
+            this.lineCount = lines[lines.length - 1] === "" ? lines.length - 1 : lines.length;
+        });
+    }
+}
+</script>

+ 7 - 0
persagy-vue-doc/src/PCodeGit/index.js

@@ -0,0 +1,7 @@
+import PCodeGit from "./PCodeGit";
+
+PCodeGit.install = vue => {
+    vue.component(PCodeGit.name, PCodeGit)
+};
+
+export default PCodeGit;

+ 33 - 0
persagy-vue-doc/src/PPlantUML/PPlantUML.vue

@@ -0,0 +1,33 @@
+<template>
+    <img :src='graphUrl' alt="用例图举例">
+</template>
+
+<script>
+import Axios from "axios"
+
+export default {
+    name: "PPlantUML",
+    props:{
+        src: {
+            default: '',
+            type: String
+        }
+    },
+    data(){
+        return{
+            graphUrl: ""
+        }
+    },
+    mounted() {
+        Axios.get(this.src).then(res => {
+            this.graphUrl = "https://g.gravizo.com/svg?"+ res.data.replace(/\n/g,";");
+        }).catch(err => {
+            console.log(err)
+        })
+    }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 7 - 0
persagy-vue-doc/src/PPlantUML/index.js

@@ -0,0 +1,7 @@
+import PPlantUML from "./PPlantUML";
+
+PPlantUML.install = vue => {
+    vue.component(PPlantUML.name, PPlantUML)
+};
+
+export default PPlantUML;

+ 61 - 0
persagy-vue-doc/src/PTableDesign/PTableDesign.vue

@@ -0,0 +1,61 @@
+<template>
+    <div>
+        <table>
+            <thead>
+            <tr>
+                <th style="width: 150px">字段名</th>
+                <th style="min-width: 200px">说明</th>
+                <th style="min-width: 100px">类型</th>
+                <th style="min-width: 50px">长度</th>
+                <th>可为空</th>
+                <th>默认值</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr v-for="col in tableInfo.columnList" :key="schema + '/' + table + ':' + col.name">
+                <td style="text-align: center">{{col.name}}</td>
+                <td>{{col.comment}}</td>
+                <td style="text-align: center">{{col.type}}</td>
+                <td style="text-align: right">{{col.length}}</td>
+                <td style="text-align: center">{{col.nullable}}</td>
+                <td style="text-align: center">{{col.default}}</td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts">
+import Axios from "axios"
+
+export default {
+    name: "PTableDesign",
+    props: {
+        sys: {
+            type: String,
+            required: true
+        },
+        schema: {
+            type: String,
+            default: "public"
+        },
+        table: {
+            type: String,
+            required: true
+        }
+    },
+    data: function() {
+        return {
+            tableInfo: {}
+        };
+    },
+    created() {
+        Axios({
+            method: "get",
+            url: `/${this.sys}/--database-doc--/table-info?schema=${this.schema}&table=${this.table}`,
+        }).then(res => {
+            this.tableInfo = res.data;
+        });
+    }
+}
+</script>

+ 7 - 0
persagy-vue-doc/src/PTableDesign/index.js

@@ -0,0 +1,7 @@
+import PTableDesign from "./PTableDesign";
+
+PTableDesign.install = vue => {
+    vue.component(PTableDesign.name, PTableDesign)
+};
+
+export default PTableDesign;

+ 30 - 0
persagy-vue-doc/src/index.js

@@ -0,0 +1,30 @@
+// 导入组件
+import PCodeGit from "./PCodeGit"
+import PPlantUML from "./PPlantUML"
+import PTableDesign from "./PTableDesign"
+
+// 存储组件列表
+const Components = [
+    PCodeGit,
+    PPlantUML,
+    PTableDesign
+]
+
+// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
+const install = function (Vue) {
+    // 判断是否安装
+    if (install.installed) {
+        return
+    }
+    // 遍历注册全局组件
+    Components.map(component => Vue.component(component.name, component));
+}
+
+/* 支持使用标签的方式引入 */
+if (typeof window !== 'undefined' && window.Vue) {
+    install(window.Vue);
+}
+
+Components.install = install;
+
+export default Components;

+ 59 - 0
persagy-vue-doc/webpack.components.config.js

@@ -0,0 +1,59 @@
+const path = require('path');
+// const webpack = require('webpack');
+//
+const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器
+
+/** 判断是生产环境还是开发环境 */
+// const isProd = process.env.NODE_ENV === 'production';
+
+const config = {
+    entry: {
+        index: "./src/index.js",
+        PCodeGit: './src/PCodeGit/index.js',
+        PPlantUML: './src/PPlantUML/index.js',
+        PTableDesign: './src/PTableDesign/index.js',
+    },
+    output: {
+        filename: '[name].js',
+        path: __dirname + '/lib',
+        library: 'sybotan-vue-doc',     // 指定的就是你使用 require 时的模块名
+        libraryTarget: 'umd',           // libraryTarget 会生成不同umd的代码,可以只是 commonjs 标准的,也可以是指amd标准的,也可以只是通过 script 标签引入的
+        umdNamedDefine: true,           // 会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define
+    },
+    module: {
+        rules: [
+            {
+                test: /\.vue$/,
+                use: [
+                    'thread-loader', 'cache-loader',
+                    {
+                        loader: 'vue-loader',
+                        options: {
+                            // loaders: {
+                            //     css: cssConfig,
+                            //     stylus: stylusConfig
+                            // },
+                            preserveWhitespace: false           // 不要留空白
+                        }
+                    }],
+                include: [path.resolve(__dirname, 'src')]
+            }
+        ]
+    },
+    plugins: [
+        new VueLoaderPlugin(), // vue加载器
+    ],
+    resolve: { // 配置路径别名
+        extensions: ['.js', '.vue', '.styl'], // import引入文件的时候不用加后缀
+    },
+    externals: {
+        vue: {
+            root: 'Vue',
+            commonjs: 'vue',
+            commonjs2: 'vue',
+            amd: 'vue'
+        }
+    }
+};
+
+module.exports = config;

+ 278 - 0
persagy-vue-doc/webpack.config.js

@@ -0,0 +1,278 @@
+const path = require('path');
+const webpack = require('webpack');
+const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成index.html
+const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 文本分离插件,分离js和css
+const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清理垃圾文件
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+
+const WebpackBar = require('webpackbar');
+
+const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器
+
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); // 为模块提供中间缓存,缓存默认的存放路径是: node_modules/.cache/hard-source
+
+/**
+ * 判断是生产环境还是开发环境
+ * @type {boolean}
+ * isProd为true表示生产
+ */
+const isProd = process.env.NODE_ENV === 'production';
+
+
+// 获取本机ip
+const getIp = require('./get_ip')();
+
+// 获取时间
+const TimeFn = require('./get_time');
+
+console.log(
+    `
+                   _ooOoo_
+                  o8888888o
+                  88" . "88
+                  (| -_- |)
+                  O\\  =  /O
+               ____/\`---'\\____
+             .'  \\\\|     |//  \`.
+            /  \\\\|||  :  |||//  \\
+           /  _||||| -:- |||||-  \\
+           |   | \\\\\\  -  /// |   |
+           | \\_|  ''\\---/''  |   |
+           \\  .-\\__  \`-\`  ___/-. /
+         ___\`. .'  /--.--\\  \`. . __
+      ."" '<  \`.___\\_<|>_/___.'  >'"".
+     | | :  \`- \\\`.;\`\\ _ /\`;.\`/ - \` : | |
+     \\  \\ \`-.   \\_ __\\ /__ _/   .-\` /  /
+======\`-.____\`-.___\\_____/___.-\`____.-'======
+                   \`=---='
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+         佛祖保佑       永无BUG
+               ${TimeFn()}
+    `
+);
+
+/**
+ *  css和stylus开发、生产依赖
+ *  生产分离css
+ */
+const cssConfig = [
+    isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
+    'thread-loader',
+    {
+        loader: 'css-loader',
+        options: {
+            sourceMap: !isProd
+        }
+    },
+    'postcss-loader'
+];
+const stylusConfig = [
+    isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader',
+    'thread-loader',
+    {
+        loader: 'css-loader',
+        options: {
+            sourceMap: !isProd
+        }
+    },
+    {
+        loader: 'stylus-loader',
+        options: {
+            sourceMap: !isProd
+        }
+    }, {
+        loader: 'style-resources-loader',
+        options: {
+            injector: 'prepend',
+            patterns: path.resolve(__dirname, 'src/assets/stylus/variables.styl')
+        }
+    }
+];
+
+const config = {
+    entry: {
+        index: isProd ? ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'] : './src/main.js' // 入口文件
+        // index: ['core-js/stable', 'regenerator-runtime/runtime', './src/main.js'], // 入口文件
+    },
+    output: {
+        path: path.resolve(__dirname, 'production'),
+        filename: isProd ? 'javascript/[name].[hash:8].js' : '[name].js', // [name] 是entry的key
+        publicPath: isProd ? './' : '/'
+        // publicPath: './',
+    },
+    module: {
+        rules: [
+            {
+                test: /\.css$/,
+                use: cssConfig
+            },
+            {
+                test: /\.styl(us)?$/,
+                use: stylusConfig,
+                include: [path.resolve(__dirname, 'src')]
+            },
+            {
+                test: /\.vue$/,
+                use: [
+                    'thread-loader', 'cache-loader',
+                    {
+                        loader: 'vue-loader',
+                        options: {
+                            loaders: {
+                                css: cssConfig,
+                                stylus: stylusConfig
+                            },
+                            preserveWhitespace: false // 不要留空白
+                        }
+                    }],
+                include: [path.resolve(__dirname, 'src')]
+            },
+            {
+                test: /\.js$/,
+                use: [
+                    'thread-loader', 'cache-loader',
+                    {
+                        loader: 'babel-loader',
+                        options: {
+                            cacheDirectory: !isProd
+                        }
+                    }
+                ],
+                exclude: (file) => (
+                    /node_modules/.test(file) && !/\.vue\.js/.test(file)
+                )
+            },
+            {
+                test: /\.svg$/,
+                use: ['thread-loader', 'babel-loader', 'vue-svg-loader'],
+                include: [path.resolve(__dirname, 'src')]
+            },
+            {
+                test: /\.(png|jpe?g|gif|bmp)$/,
+                use: [
+                    {
+                        loader: 'url-loader',
+                        options: { // 配置图片编译路径
+                            limit: 8192, // 小于8k将图片转换成base64
+                            name: '[name].[ext]?[hash:8]',
+                            outputPath: 'images/'
+                        }
+                    }],
+                include: [path.resolve(__dirname, 'src')]
+            },
+            {
+                test: /\.html$/,
+                use: [{
+                    loader: 'html-loader',
+                    options: { // 配置html中图片编译
+                        minimize: true,
+                        attributes: false
+                    }
+                }]
+            }
+        ]
+    },
+    resolve: { // 配置路径别名
+        extensions: ['.js', '.vue', '.styl'], // import引入文件的时候不用加后缀
+        modules: [
+            'node_modules',
+            path.resolve(__dirname, 'src/assets'),
+            path.resolve(__dirname, 'src/docs'),
+            path.resolve(__dirname, 'src/utils')
+        ]
+    },
+    plugins: [
+        new webpack.BannerPlugin(`@meri-design ${TimeFn()}`),
+        new HardSourceWebpackPlugin(),
+        new VueLoaderPlugin(), // vue加载器
+        new CopyWebpackPlugin([{
+            from: path.resolve(__dirname, 'node_modules/vue/dist/vue.min.js'),
+            to: 'modules'
+        }, {
+            from: path.resolve(__dirname, 'node_modules/vuex/dist/vuex.min.js'),
+            to: 'modules'
+        }, {
+            from: path.resolve(__dirname, 'node_modules/vue-router/dist/vue-router.min.js'),
+            to: 'modules'
+        }]),
+        new HtmlWebpackPlugin({
+            template: path.join(__dirname, 'src/index.html'), // 引入模版
+            favicon: path.join(__dirname, 'src/assets/favicon.ico'),
+            filename: 'index.html',
+            minify: { // 对index.html压缩
+                collapseWhitespace: isProd, // 去掉index.html的空格
+                removeAttributeQuotes: isProd // 去掉引号
+            },
+            hash: true, // 去掉上次浏览器的缓存(使浏览器每次获取到的是最新的html)
+            // ,chunks:['vendor','main'] // 在产出的html文件里面引入哪些代码块,里面的名字要跟entry里面key对应(一般用于多文件入口)
+            inlineSource: '.(js|css)'
+        }),
+        new WebpackBar({
+            color: '#0091ff'
+        })
+    ],
+    externals: {
+        vue: 'Vue',
+        vuex: 'Vuex',
+        'vue-router': 'VueRouter'
+    }
+};
+
+if (isProd) {
+    config.plugins.push(
+        new CleanWebpackPlugin({
+            verbose: true, // 打印被删除的文件
+            protectWebpackAssets: false, // 允许删除cleanOnceBeforeBuildPatterns中的文件
+            cleanOnceBeforeBuildPatterns: ['**/*', path.resolve(__dirname, 'production')]
+        }),
+        new MiniCssExtractPlugin({ // 分离css
+            filename: 'stylesheets/[name].[contenthash:8].css'
+            // chunkFilename: isProd?'stylesheets/[name].[contenthash:8].css':'[name].css'
+        })
+    );
+
+    config.optimization = { // 抽离第三方插件
+        splitChunks: {
+            chunks: 'all', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
+            minSize: 10000, // 提高缓存利用率,这需要在http2/spdy
+            maxSize: 0, // 没有限制
+            minChunks: 3, // 共享最少的chunk数,使用次数超过这个值才会被提取
+            maxAsyncRequests: 5, // 最多的异步chunk数
+            maxInitialRequests: 5, // 最多的同步chunks数
+            name: true,
+            cacheGroups: { // 这里开始设置缓存的 chunks
+                vendor: { // key 为entry中定义的 入口名称,new webpack.ProvidePlugin中的库
+                    test: /node_modules/, // 正则规则验证,如果符合就提取 chunk (指定是node_modules下的第三方包)
+                    name: 'vendor', // 要缓存的 分隔出来的 chunk 名称
+                    enforce: true
+                },
+                styles: {
+                    test: /src\.(css|styl)$/,
+                    name: 'main',
+                    enforce: true
+                }
+            }
+        },
+        runtimeChunk: { name: 'manifest' } // 为每个入口提取出webpack runtime模块
+    };
+} else {
+    config.devtool = 'source-map'; // 如果只用source-map开发环境出现错误定位源文件,生产环境会生成map文件
+    config.devServer = {
+        contentBase: path.join(__dirname, 'production'), // 将 dist 目录下的文件,作为可访问文件。
+        compress: true, // 开启Gzip压缩
+        // , host: 'localhost' // 设置服务器的ip地址,默认localhost
+        host: getIp, // 设置服务器的ip地址,默认localhost
+        port: 3002, // 端口号
+        open: true, // 自动打开浏览器
+        hot: true,
+        overlay: { // 当出现编译器错误或警告时,就在网页上显示一层黑色的背景层和错误信息
+            errors: true
+        },
+        disableHostCheck: true //  不检查主机
+        // historyApiFallback: { // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 /
+        //     rewrites: [{ from: /./, to: '/' }]
+        // }
+    };
+}
+
+module.exports = config;