├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── CHANGELOG.md ├── README.md ├── config ├── dev.env.js ├── index.js ├── prod.env.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.client.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.server.conf.js ├── package.json ├── scripts ├── build-server.js ├── build.js ├── check-versions.js ├── dev-server.js ├── server-build-client.js ├── server-check-schema.js ├── server-copy-config.js ├── server-generate-library-info.js ├── server-template-archive.js └── utils-schema-validator.js ├── server ├── node.js └── preview-inserted-script.js └── src ├── App.vue ├── components ├── pipeline-gap-demo │ ├── config │ │ ├── data.json │ │ └── schema.js │ ├── index.vue │ └── package.json ├── pipeline-header-demo │ ├── config │ │ ├── data.json │ │ └── schema.js │ ├── index.vue │ └── package.json ├── pipeline-info-demo │ ├── config │ │ ├── data.json │ │ └── schema.js │ ├── index.vue │ └── package.json └── pipeline-weather-demo │ ├── config │ ├── data.json │ └── schema.js │ ├── index.vue │ └── package.json ├── config ├── base-config-schema.json ├── base-config.json └── components.json ├── create-app.js ├── index.html ├── main-server.js ├── main.js └── static └── css ├── app.less └── basic.less /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", { 5 | "modules": false, 6 | "targets": { 7 | "browsers": ["iOS >= 7", "Android >= 4"] 8 | } 9 | } 10 | ], 11 | "stage-2" 12 | ], 13 | "plugins": [ 14 | "transform-runtime" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.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 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/** 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | es6: true 12 | }, 13 | extends: 'airbnb-base', 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | // check if imports actually resolve 19 | settings: { 20 | 'import/resolver': { 21 | 'webpack': { 22 | 'config': 'config/webpack.base.conf.js' 23 | } 24 | } 25 | }, 26 | // add your custom rules here 27 | rules: { 28 | 'import/no-unresolved': 'off', 29 | 'import/extensions': 'off', 30 | 'import/first': 'off', 31 | 'import/no-dynamic-require': 'off', 32 | 'import/no-extraneous-dependencies': 'off', 33 | 'import/no-named-as-default-member': 'off', 34 | 'linebreak-style': 'off', 35 | 'global-require': 'off', 36 | 'no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true }], 37 | 'comma-dangle': ['error', 'only-multiline'], 38 | 'no-param-reassign': ['error', { 'props': false }], 39 | 'no-plusplus': ['error', { 'allowForLoopAfterthoughts': true }], 40 | 'no-restricted-syntax': 'off', 41 | 'guard-for-in': 'off', 42 | 'no-unname-function': 'off', 43 | // allow debugger during development 44 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | server/* 5 | !server/node.js 6 | !server/preview-inserted-script.js 7 | pipeline-template.zip 8 | .log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | package-lock.json 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [0.1.1](https://github.com/page-pipepline/pipeline-template/compare/v0.1.0...v0.1.1) (2018-07-29) 7 | 8 | 9 | 10 | 11 | # 0.1.0 (2018-07-12) 12 | 13 | 14 | ### Bug Fixes 15 | 16 | * color data should be hex ([0e4561c](https://github.com/page-pipepline/pipeline-template/commit/0e4561c)) 17 | * color data should be hex ([cfd8844](https://github.com/page-pipepline/pipeline-template/commit/cfd8844)) 18 | * console.error -> console.log ([f23a435](https://github.com/page-pipepline/pipeline-template/commit/f23a435)) 19 | * hold image position ([113b06b](https://github.com/page-pipepline/pipeline-template/commit/113b06b)) 20 | * preview inserted script error ([9f8d673](https://github.com/page-pipepline/pipeline-template/commit/9f8d673)) 21 | * 页面基础配置需要全局替换 ([a7b8e91](https://github.com/page-pipepline/pipeline-template/commit/a7b8e91)) 22 | 23 | 24 | ### Features 25 | 26 | * add library components drag-and-drop ([52802c5](https://github.com/page-pipepline/pipeline-template/commit/52802c5)) 27 | * add SSR validate script ([9149d24](https://github.com/page-pipepline/pipeline-template/commit/9149d24)) 28 | * remove library ([a83e92b](https://github.com/page-pipepline/pipeline-template/commit/a83e92b)) 29 | * 添加动态接口查询组件示例 ([edcade1](https://github.com/page-pipepline/pipeline-template/commit/edcade1)) 30 | 31 | 32 | ### BREAKING CHANGES 33 | 34 | * not support library 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pipeline-template 2 | 3 | > 页面可视化搭建框架的页面模板 -- 基于 [vue](https://github.com/vuejs/vue) 4 | 5 | ## 用法 6 | 7 | ### 初始化 8 | 9 | ```bash 10 | # 初始化项目(安装依赖包) 11 | npm i 12 | ``` 13 | 14 | ### 本地测试 15 | ``` 16 | npm start 17 | ``` 18 | 19 | ### 生成模板 20 | * 生成后台渲染所需代码 21 | ``` 22 | $ npm run server 23 | ``` 24 | 打包结果在`server`目录中。 25 | 26 | * 验证后台渲染可用 27 | 28 | 后台渲染对代码写法是有一些要求的, 比如不允许使用 window/document 这种浏览器特有对象. 29 | 所以可以本地执行后台渲染来验证后台渲染是否正常. 30 | 31 | ``` 32 | $ npm run render 33 | ``` 34 | 35 | * 生成模板压缩包 36 | ``` 37 | $ npm run server 38 | $ npm run template 39 | ``` 40 | 41 | 打包结果为`pipeline-template.zip`, 提交模板时, 提交该 zip 文件. 42 | 43 | ### 个性化页面独立发布 44 | 拉取一个独立分支或一份独立源码, 然后 45 | 46 | ``` 47 | $ npm run build 48 | ``` 49 | 50 | 打包结果在`dist`目录中。 51 | 52 | ## 后台渲染脚本 53 | 路径 `server/node.js` 54 | 55 | 用于在 node 后台渲染出带 DOM 元素的 `index.html`. 56 | 57 | ### 渲染发布版本 `默认` 58 | ``` 59 | $ node server/node.js release 60 | ``` 61 | 62 | ### 渲染页面预览版本 63 | > 嵌入了模板生成页面的调试脚本 64 | ``` 65 | $ node server/node.js preview 66 | ``` 67 | 68 | ## TODO 69 | * [x] 基础样式的引入方式 70 | * [x] 模板打包为压缩包脚本 71 | * [x] schema 和 data 的验证工具: [schema-tool](https://page-pipepline.github.io/pipeline-editor/dist/#/schema) 72 | * [ ] ~~组件开发套件~~ 73 | * [ ] ~~组件抽离为 npm 包~~ 74 | 75 | ## 前后端同构已知问题 76 | 77 | ### 页面基本配置的更新在本地 dev 模式下无法实时渲染 78 | 因为页面基本配置`base-config.json`, 是在获取 webpack 构建参数时候引入给 html-webpack-plugin 的, 79 | 属于 webpack-dev-tool 的一部分, 所以文件变化时, webpack-dev-tool 并不会重新引入该文件. 80 | 81 | 好在: 需要调试页面基本配置的场景比较少. 82 | 83 | ## EOF 84 | 85 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const prodEnv = require('./prod.env'); 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }); 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // Template version: 1.1.3 2 | // see http://vuejs-templates.github.io/webpack for documentation. 3 | const path = require('path'); 4 | const argv = require('yargs').argv; 5 | 6 | // 引入页面的基础配置, 用于 htmlWebpackPlugin 生成页面时候替换成对应的内容 7 | const baseConfig = require('../src/config/base-config.json'); 8 | 9 | const HWPPageBaseConfig = Object.keys(baseConfig).reduce((accumulator, key) => { 10 | accumulator[key] = baseConfig[key]; 11 | return accumulator; 12 | }, {}); 13 | 14 | const HWPPageBaseConfigForServer = Object.keys(baseConfig).reduce((accumulator, key) => { 15 | accumulator[key] = ``; 16 | return accumulator; 17 | }, {}); 18 | 19 | module.exports = { 20 | build: { 21 | env: require('./prod.env'), 22 | index: path.resolve(__dirname, '../dist/pipeline/index.html'), 23 | assetsRoot: path.resolve(__dirname, '../dist/pipeline'), 24 | assetsPublicPath: './', 25 | productionSourceMap: true, 26 | // Run the build command with an extra argument to 27 | // View the bundle analyzer report after build finishes: 28 | // `npm run build -- --report` 29 | // Set to `true` or `false` to always turn it on or off 30 | bundleAnalyzerReport: !!argv.report, 31 | HWPPageBaseConfig 32 | }, 33 | dev: { 34 | env: require('./dev.env'), 35 | port: 3001, 36 | autoOpenBrowser: true, 37 | assetsPublicPath: '/pipeline/', 38 | proxyTable: {}, 39 | // CSS Sourcemaps off by default because relative paths are "buggy" 40 | // with this option, according to the CSS-Loader README 41 | // (https://github.com/webpack/css-loader#sourcemaps) 42 | // In our experience, they generally work as expected, 43 | // just be aware of this issue when enabling this option. 44 | cssSourceMap: false, 45 | // 是否启用移动端调试工具vconsole 46 | // `npm start -- --debug` 47 | // Set to `true` or `false` to always turn it on or off 48 | vConsole: !!argv.debug, 49 | HWPPageBaseConfig 50 | }, 51 | server: { 52 | HWPPageBaseConfigForServer, 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | }; 4 | -------------------------------------------------------------------------------- /config/utils.js: -------------------------------------------------------------------------------- 1 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 2 | 3 | exports.cssLoaders = (_options) => { 4 | const options = _options || {}; 5 | 6 | const cssLoader = { 7 | loader: 'css-loader', 8 | options: { 9 | sourceMap: options.sourceMap 10 | } 11 | }; 12 | 13 | // generate loader string to be used with extract text plugin 14 | function generateLoaders(loader, loaderOptions) { 15 | const loaders = [cssLoader]; 16 | if (loader) { 17 | // add postcss 18 | loaders.push({ 19 | loader: 'postcss-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | }); 24 | loaders.push({ 25 | loader: `${loader}-loader`, 26 | options: Object.assign({}, loaderOptions, { 27 | sourceMap: options.sourceMap 28 | }) 29 | }); 30 | } 31 | 32 | // Extract CSS when that option is specified 33 | // (which is the case during production build) 34 | if (options.extract) { 35 | return ExtractTextPlugin.extract({ 36 | use: loaders, 37 | fallback: 'vue-style-loader' 38 | }); 39 | } 40 | return ['vue-style-loader'].concat(loaders); 41 | } 42 | 43 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 44 | return { 45 | css: generateLoaders(), 46 | less: generateLoaders('less'), 47 | // sass: generateLoaders('sass', { indentedSyntax: true }), 48 | // scss: generateLoaders('sass'), 49 | // stylus: generateLoaders('stylus'), 50 | // styl: generateLoaders('stylus') 51 | }; 52 | }; 53 | 54 | // Generate loaders for standalone style files (outside of .vue) 55 | exports.styleLoaders = (options) => { 56 | const output = []; 57 | const loaders = exports.cssLoaders(options); 58 | for (const extension in loaders) { 59 | const loader = loaders[extension]; 60 | output.push({ 61 | test: new RegExp(`\\.${extension}$`), 62 | use: loader 63 | }); 64 | } 65 | return output; 66 | }; 67 | -------------------------------------------------------------------------------- /config/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils'); 2 | 3 | const isProduction = process.env.NODE_ENV === 'production'; 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: false, // 会导致动态加载的样式带有sourcemap,先去掉 8 | extract: isProduction 9 | }) 10 | }; 11 | -------------------------------------------------------------------------------- /config/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const vueLoaderConfig = require('./vue-loader.conf'); 3 | const webpack = require('webpack'); 4 | 5 | function resolve(dir) { 6 | return path.join(__dirname, '..', dir); 7 | } 8 | 9 | const loaderIncDir = [resolve('src'), resolve('components'), resolve('test')]; 10 | const loaderExcludeDir = []; 11 | 12 | module.exports = { 13 | entry: { 14 | }, 15 | resolve: { 16 | extensions: ['.js', '.vue', '.json', '.less'], 17 | alias: { 18 | vue$: 'vue/dist/vue.esm.js', 19 | '@': resolve('src'), 20 | bcomp: resolve('src/base-components'), 21 | comp: resolve('src/components'), 22 | static: resolve('src/static'), 23 | } 24 | }, 25 | module: { 26 | rules: [ 27 | { 28 | test: /\.(js|vue)$/, 29 | loader: 'eslint-loader', 30 | enforce: 'pre', 31 | include: loaderIncDir, 32 | exclude: loaderExcludeDir, 33 | options: { 34 | formatter: require('eslint-friendly-formatter') 35 | } 36 | }, 37 | { 38 | test: /\.vue$/, 39 | loader: 'vue-loader', 40 | include: loaderIncDir, 41 | options: vueLoaderConfig 42 | }, 43 | { 44 | test: /\.js$/, 45 | loader: 'babel-loader', 46 | include: loaderIncDir, 47 | exclude: loaderExcludeDir, 48 | options: { 49 | cacheDirectory: true, 50 | } 51 | }, 52 | { 53 | test: /\.(png|jpe?g|gif)(\?.*)?$/, 54 | loader: 'url-loader', 55 | options: { 56 | limit: 10000, 57 | name: 'img/[name].[hash:8].[ext]', 58 | fallback: 'file-loader', 59 | publicPath: '..', 60 | } 61 | }, 62 | { 63 | test: /\.svg$/, 64 | use: [ 65 | 'svg-sprite-loader', 66 | 'svgo-loader' 67 | ] 68 | }, 69 | { 70 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 71 | loader: 'url-loader', 72 | options: { 73 | limit: 10000, 74 | name: 'fonts/[name].[hash:8].[ext]' 75 | } 76 | }, 77 | ] 78 | }, 79 | plugins: [ 80 | new webpack.ProvidePlugin({ 81 | Promise: 'imports-loader?this=>global!exports-loader?global.Promise!es6-promise/auto', 82 | fetch: 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch' 83 | }), 84 | ] 85 | }; 86 | -------------------------------------------------------------------------------- /config/webpack.client.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const utils = require('./utils'); 3 | const webpack = require('webpack'); 4 | const config = require('.'); 5 | const merge = require('webpack-merge'); 6 | const baseWebpackConfig = require('./webpack.base.conf'); 7 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 8 | const VueSSRClientPlugin = require('vue-server-renderer/client-plugin'); 9 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); 10 | 11 | const env = config.build.env; 12 | 13 | const webpackConfig = merge(baseWebpackConfig, { 14 | entry: { 15 | app: ['./src/main.js'], 16 | }, 17 | externals: { 18 | './config/components': { 19 | commonjs2: '../config/components.json', 20 | commonjs: '../config/components.json', 21 | }, 22 | }, 23 | module: { 24 | rules: utils.styleLoaders({ 25 | sourceMap: false, // 会导致动态加载的样式带有sourcemap,先去掉 26 | extract: true 27 | }) 28 | }, 29 | // devtool: config.build.productionSourceMap ? '#source-map' : false, 30 | output: { 31 | path: path.join(__dirname, '..', 'server', 'dist'), 32 | filename: 'js/[name].[chunkhash:8].js', 33 | chunkFilename: 'js/[id].[chunkhash:8].js', 34 | publicPath: './' 35 | }, 36 | plugins: [ 37 | new VueSSRClientPlugin(), 38 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify 39 | new webpack.optimize.UglifyJsPlugin({ 40 | compress: { 41 | warnings: false, 42 | }, 43 | sourceMap: true, 44 | comments: false, 45 | }), 46 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 47 | new webpack.DefinePlugin({ 48 | 'process.env': env 49 | }), 50 | // extract css into its own file 51 | new ExtractTextPlugin({ 52 | filename: 'css/[name].[contenthash:8].css', 53 | }), 54 | // Compress extracted CSS. We are using this plugin so that possible 55 | // duplicated CSS from different components can be deduped. 56 | // 这里关闭 http://cssnano.co/optimisations/reducetransforms/ 这个选项,因为会导致ios下切页动画闪烁 57 | // 注意,这里是cssnano 3.x.x的语法,以后升级到4+配置语法会变! 58 | new OptimizeCSSPlugin({ 59 | cssProcessorOptions: { 60 | safe: true, 61 | postcssReduceTransforms: { 62 | disable: true 63 | }, 64 | } 65 | }), 66 | // https://webpack.js.org/plugins/module-concatenation-plugin/ 67 | new webpack.optimize.ModuleConcatenationPlugin(), 68 | // keep module.id stable when vender modules does not change 69 | new webpack.HashedModuleIdsPlugin(), 70 | ] 71 | }); 72 | 73 | module.exports = webpackConfig; 74 | -------------------------------------------------------------------------------- /config/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils'); 2 | const webpack = require('webpack'); 3 | const config = require('.'); 4 | const merge = require('webpack-merge'); 5 | const baseWebpackConfig = require('./webpack.base.conf'); 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin'); 8 | const VConsolePlugin = require('vconsole-webpack-plugin'); 9 | 10 | const port = process.env.PORT || config.dev.port; 11 | 12 | // add hot-reload related code to entry chunks 13 | Object.keys(baseWebpackConfig.entry).forEach((name) => { 14 | // baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 15 | baseWebpackConfig.entry[name].unshift(`webpack-dev-server/client?http://0.0.0.0:${port}/`, 'webpack/hot/only-dev-server'); 16 | }); 17 | 18 | module.exports = merge(baseWebpackConfig, { 19 | entry: { 20 | app: ['./src/main.js'], 21 | // info 存在加载顺序的问题,只能单独抽出来 22 | vendor: [ 23 | 'vue', 24 | ] 25 | }, 26 | module: { 27 | // dev模式不使用Extract CSS,与热更新一起使用会报错 28 | rules: utils.styleLoaders({ 29 | sourceMap: config.dev.cssSourceMap 30 | }) 31 | }, 32 | output: { 33 | path: config.build.assetsRoot, 34 | filename: 'js/[name].debug.js', 35 | chunkFilename: 'js/[id].debug.js', 36 | publicPath: config.dev.assetsPublicPath 37 | }, 38 | // cheap-module-eval-source-map is faster for development 39 | devtool: '#cheap-module-eval-source-map', 40 | plugins: [ 41 | new webpack.DefinePlugin({ 42 | 'process.env': config.dev.env 43 | }), 44 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 45 | new webpack.HotModuleReplacementPlugin(), 46 | new webpack.NoEmitOnErrorsPlugin(), 47 | new VConsolePlugin({ enable: config.dev.vConsole }), 48 | // https://github.com/ampedandwired/html-webpack-plugin 49 | new HtmlWebpackPlugin({ 50 | vueInstancePlaceholder: '
', 51 | filename: 'index.html', 52 | template: 'src/index.html', 53 | inject: true, 54 | ...config.dev.HWPPageBaseConfig 55 | }), 56 | new FriendlyErrorsPlugin() 57 | ] 58 | }); 59 | -------------------------------------------------------------------------------- /config/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils'); 2 | const webpack = require('webpack'); 3 | const config = require('.'); 4 | const merge = require('webpack-merge'); 5 | const baseWebpackConfig = require('./webpack.base.conf'); 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 8 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); 9 | 10 | const env = config.build.env; 11 | 12 | const webpackConfig = merge(baseWebpackConfig, { 13 | entry: { 14 | app: ['./src/main.js'], 15 | // info 存在加载顺序的问题,只能单独抽出来 16 | vendor: [ 17 | 'vue', 18 | ] 19 | }, 20 | module: { 21 | rules: utils.styleLoaders({ 22 | sourceMap: false, // 会导致动态加载的样式带有sourcemap,先去掉 23 | extract: true 24 | }) 25 | }, 26 | // devtool: config.build.productionSourceMap ? '#source-map' : false, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: 'js/[name].[chunkhash:8].js', 30 | chunkFilename: 'js/[id].[chunkhash:8].js', 31 | publicPath: config.build.assetsPublicPath 32 | }, 33 | plugins: [ 34 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 35 | new webpack.DefinePlugin({ 36 | 'process.env': env 37 | }), 38 | // split vendor js into its own file 39 | new webpack.optimize.CommonsChunkPlugin({ 40 | name: 'vendor', 41 | // (with more entries, this ensures that no other module 42 | // goes into the vendor chunk) 43 | minChunks: Infinity 44 | }), 45 | // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify 46 | new webpack.optimize.UglifyJsPlugin({ 47 | compress: { 48 | warnings: false, 49 | }, 50 | sourceMap: true, 51 | comments: false, 52 | }), 53 | // extract css into its own file 54 | new ExtractTextPlugin({ 55 | filename: 'css/[name].[contenthash:8].css' 56 | }), 57 | // Compress extracted CSS. We are using this plugin so that possible 58 | // duplicated CSS from different components can be deduped. 59 | // 这里关闭 http://cssnano.co/optimisations/reducetransforms/ 这个选项,因为会导致ios下切页动画闪烁 60 | // 注意,这里是cssnano 3.x.x的语法,以后升级到4+配置语法会变! 61 | new OptimizeCSSPlugin({ 62 | cssProcessorOptions: { 63 | safe: true, 64 | postcssReduceTransforms: { 65 | disable: true 66 | }, 67 | } 68 | }), 69 | // generate dist index.html with correct asset hash for caching. 70 | // you can customize output by editing /index.html 71 | // see https://github.com/ampedandwired/html-webpack-plugin 72 | new HtmlWebpackPlugin({ 73 | vueInstancePlaceholder: '', 74 | filename: config.build.index, 75 | template: 'src/index.html', 76 | inject: true, 77 | minify: { 78 | removeComments: true, 79 | collapseWhitespace: true, 80 | // more options: 81 | // https://github.com/kangax/html-minifier#options-quick-reference 82 | }, 83 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 84 | chunksSortMode: 'dependency', 85 | ...config.build.HWPPageBaseConfig 86 | }), 87 | // https://webpack.js.org/plugins/module-concatenation-plugin/ 88 | new webpack.optimize.ModuleConcatenationPlugin(), 89 | // keep module.id stable when vender modules does not change 90 | new webpack.HashedModuleIdsPlugin(), 91 | ] 92 | }); 93 | 94 | if (config.build.bundleAnalyzerReport) { 95 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 96 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()); 97 | } 98 | 99 | module.exports = webpackConfig; 100 | -------------------------------------------------------------------------------- /config/webpack.server.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const utils = require('./utils'); 3 | const webpack = require('webpack'); 4 | const config = require('.'); 5 | const merge = require('webpack-merge'); 6 | const baseWebpackConfig = require('./webpack.base.conf'); 7 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 8 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 9 | const VueSSRServerPlugin = require('vue-server-renderer/server-plugin'); 10 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); 11 | 12 | const env = config.build.env; 13 | 14 | const webpackConfig = merge(baseWebpackConfig, { 15 | entry: { 16 | app: ['./src/main-server.js'], 17 | }, 18 | externals: { 19 | './config/components': { 20 | commonjs2: '../config/components.json', 21 | commonjs: '../config/components.json', 22 | }, 23 | vue: 'vue', 24 | }, 25 | module: { 26 | rules: utils.styleLoaders({ 27 | sourceMap: false, // 会导致动态加载的样式带有sourcemap,先去掉 28 | extract: true 29 | }) 30 | }, 31 | target: 'node', 32 | // devtool: config.build.productionSourceMap ? '#source-map' : false, 33 | output: { 34 | libraryTarget: 'commonjs2', 35 | path: path.join(__dirname, '..', 'server', 'dist'), 36 | filename: 'js/[name].[chunkhash:8].js', 37 | chunkFilename: 'js/[id].[chunkhash:8].js', 38 | publicPath: './' 39 | }, 40 | plugins: [ 41 | new VueSSRServerPlugin(), 42 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 43 | new webpack.DefinePlugin({ 44 | 'process.env': env 45 | }), 46 | // extract css into its own file 47 | new ExtractTextPlugin({ 48 | filename: 'css/[name].[contenthash:8].css', 49 | }), 50 | // Compress extracted CSS. We are using this plugin so that possible 51 | // duplicated CSS from different components can be deduped. 52 | // 这里关闭 http://cssnano.co/optimisations/reducetransforms/ 这个选项,因为会导致ios下切页动画闪烁 53 | // 注意,这里是cssnano 3.x.x的语法,以后升级到4+配置语法会变! 54 | new OptimizeCSSPlugin({ 55 | cssProcessorOptions: { 56 | safe: true, 57 | postcssReduceTransforms: { 58 | disable: true 59 | }, 60 | } 61 | }), 62 | // generate dist index.html with correct asset hash for caching. 63 | // you can customize output by editing /index.html 64 | // see https://github.com/ampedandwired/html-webpack-plugin 65 | new HtmlWebpackPlugin({ 66 | vueInstancePlaceholder: '', 67 | filename: path.join(__dirname, '..', 'server', 'dist', 'index-origin.html'), 68 | template: 'src/index.html', 69 | inject: false, 70 | minify: { 71 | // removeComments: true, 72 | // collapseWhitespace: true, 73 | // more options: 74 | // https://github.com/kangax/html-minifier#options-quick-reference 75 | }, 76 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 77 | chunksSortMode: 'dependency', 78 | ...config.server.HWPPageBaseConfigForServer, 79 | }), 80 | // https://webpack.js.org/plugins/module-concatenation-plugin/ 81 | new webpack.optimize.ModuleConcatenationPlugin(), 82 | // keep module.id stable when vender modules does not change 83 | new webpack.HashedModuleIdsPlugin() 84 | ] 85 | }); 86 | 87 | module.exports = webpackConfig; 88 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pipeline-template", 3 | "version": "0.1.1", 4 | "description": "", 5 | "scripts": { 6 | "init": "yarn -V || npm i yarn -g && yarn", 7 | "dev": "node scripts/dev-server.js", 8 | "start": "node scripts/dev-server.js", 9 | "build": "rm -rf dist & node scripts/build.js", 10 | "server": "rm -rf server/dist && rm -rf server/config && node scripts/build-server.js", 11 | "render": "node server/node.js", 12 | "template": "node scripts/server-template-archive.js", 13 | "lint": "eslint --ext .js,.vue src", 14 | "release": "standard-version" 15 | }, 16 | "author": "CntChen", 17 | "license": "MIT", 18 | "dependencies": { 19 | "archiver": "^2.1.1", 20 | "array.prototype.find": "^2.0.0", 21 | "babel-polyfill": "^6.26.0", 22 | "babel-preset-es2015-node5": "^1.2.0", 23 | "copy-webpack-plugin": "^4.5.1", 24 | "es6-promise": "^4.0.5", 25 | "eslint-plugin-jsx-a11y": "^4.0.0", 26 | "eslint-plugin-react": "^6.10.3", 27 | "fastclick": "^1.0.6", 28 | "upgrade": "^1.1.0", 29 | "validator": "^7.0.0", 30 | "vue": "^2.5.14", 31 | "vue-server-renderer": "^2.5.14", 32 | "webpack": "^3.11.0", 33 | "whatwg-fetch": "^2.0.3" 34 | }, 35 | "devDependencies": { 36 | "autoprefixer": "^6.7.2", 37 | "babel-core": "^6.26.0", 38 | "babel-eslint": "^7.1.1", 39 | "babel-loader": "^7.0.0", 40 | "babel-plugin-import": "^1.6.2", 41 | "babel-plugin-transform-runtime": "^6.22.0", 42 | "babel-preset-env": "^1.3.2", 43 | "babel-preset-stage-0": "^6.24.1", 44 | "babel-preset-stage-2": "^6.22.0", 45 | "babel-preset-stage-3": "^6.24.1", 46 | "babel-register": "^6.22.0", 47 | "chalk": "^1.1.3", 48 | "css-loader": "^0.28.0", 49 | "cz-conventional-changelog": "^2.1.0", 50 | "eslint": "^3.19.0", 51 | "eslint-config-airbnb": "^14.1.0", 52 | "eslint-config-airbnb-base": "^11.3.0", 53 | "eslint-friendly-formatter": "^2.0.7", 54 | "eslint-import-resolver-webpack": "^0.8.3", 55 | "eslint-loader": "^1.7.1", 56 | "eslint-plugin-babel": "^4.1.1", 57 | "eslint-plugin-html": "^2.0.0", 58 | "eslint-plugin-import": "^2.7.0", 59 | "eventsource-polyfill": "^0.9.6", 60 | "exports-loader": "^0.6.4", 61 | "extract-text-webpack-plugin": "^3.0.0", 62 | "file-loader": "^1.1.4", 63 | "friendly-errors-webpack-plugin": "^1.1.3", 64 | "html-webpack-plugin": "^3.0.6", 65 | "imports-loader": "^0.7.1", 66 | "less": "^2.7.2", 67 | "less-loader": "^4.0.3", 68 | "opn": "^4.0.2", 69 | "optimize-css-assets-webpack-plugin": "^3.2.0", 70 | "ora": "^1.2.0", 71 | "postcss-loader": "^2.0.5", 72 | "semver": "^5.3.0", 73 | "shelljs": "^0.7.6", 74 | "standard-version": "^4.4.0", 75 | "svg-sprite-loader": "^2.0.5", 76 | "svgo-loader": "^1.2.1", 77 | "url-loader": "^0.5.8", 78 | "vconsole-webpack-plugin": "^1.1.2", 79 | "vue-loader": "^13.3.0", 80 | "vue-style-loader": "^3.0.1", 81 | "vue-template-compiler": "^2.5.14", 82 | "webpack-bundle-analyzer": "^2.9.0", 83 | "webpack-dev-server": "^2.7.1", 84 | "webpack-merge": "^4.1.0", 85 | "yargs": "^8.0.1" 86 | }, 87 | "engines": { 88 | "node": ">= 4.0.0", 89 | "npm": ">= 3.0.0" 90 | }, 91 | "browserslist": [ 92 | "iOS >= 7", 93 | "Android >= 4" 94 | ], 95 | "config": { 96 | "commitizen": { 97 | "path": "./node_modules/cz-conventional-changelog" 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /scripts/build-server.js: -------------------------------------------------------------------------------- 1 | // run other build task first 2 | require('./server-check-schema.js'); 3 | require('./server-copy-config.js'); 4 | require('./server-generate-library-info.js'); 5 | require('./server-build-client.js'); 6 | 7 | require('./check-versions')(); 8 | 9 | process.env.NODE_ENV = 'production'; 10 | 11 | const ora = require('ora'); 12 | const chalk = require('chalk'); 13 | const webpack = require('webpack'); 14 | const webpackConfig = require('../config/webpack.server.conf'); 15 | 16 | const spinner = ora('building for production...'); 17 | spinner.start(); 18 | 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, 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 | }); 37 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')(); 2 | 3 | process.env.NODE_ENV = 'production'; 4 | 5 | const ora = require('ora'); 6 | const chalk = require('chalk'); 7 | const webpack = require('webpack'); 8 | const webpackConfig = require('../config/webpack.prod.conf'); 9 | 10 | const spinner = ora('building for production...'); 11 | spinner.start(); 12 | 13 | webpack(webpackConfig, (err, stats) => { 14 | spinner.stop(); 15 | if (err) throw err; 16 | process.stdout.write(`${stats.toString({ 17 | colors: true, 18 | modules: false, 19 | children: false, 20 | chunks: false, 21 | chunkModules: false 22 | })}\n\n`); 23 | 24 | if (stats.hasErrors()) { 25 | console.log(chalk.red(' Build failed with errors.\n')); 26 | process.exit(1); 27 | } 28 | 29 | console.log(chalk.cyan(' Build complete.\n')); 30 | console.log(chalk.yellow( 31 | ' Tip: built files are meant to be served over an HTTP server.\n' + 32 | ' Opening index.html over file:// won\'t work.\n' 33 | )); 34 | }); 35 | -------------------------------------------------------------------------------- /scripts/check-versions.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | const semver = require('semver'); 3 | const packageConfig = require('../package.json'); 4 | const shell = require('shelljs'); 5 | 6 | function exec(cmd) { 7 | return require('child_process').execSync(cmd).toString().trim(); 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | }, 16 | ]; 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }); 24 | } 25 | 26 | module.exports = () => { 27 | const warnings = []; 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i]; 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(`${mod.name}: ${chalk.red(mod.currentVersion)} should be ${chalk.green(mod.versionRequirement)}`); 32 | } 33 | } 34 | 35 | if (warnings.length) { 36 | console.log(''); 37 | console.log(chalk.yellow('To use this template, you must update following to modules:')); 38 | console.log(); 39 | for (let i = 0; i < warnings.length; i++) { 40 | const warning = warnings[i]; 41 | console.log(` ${warning}`); 42 | } 43 | console.log(); 44 | process.exit(1); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')(); 2 | const config = require('../config'); 3 | 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV); 6 | } 7 | 8 | const opn = require('opn'); 9 | const webpack = require('webpack'); 10 | const webpackDevServer = require('webpack-dev-server'); 11 | const webpackConfig = require('../config/webpack.dev.conf'); 12 | 13 | // default port where dev server listens for incoming traffic 14 | const port = process.env.PORT || config.dev.port; 15 | // automatically open browser, if not set will be false 16 | const autoOpenBrowser = !!config.dev.autoOpenBrowser; 17 | 18 | const compiler = webpack(webpackConfig); 19 | 20 | const uri = `http://localhost:${port}${config.dev.assetsPublicPath}#/`; 21 | 22 | let _resolve; 23 | const readyPromise = new Promise((resolve) => { 24 | _resolve = resolve; 25 | }); 26 | 27 | const server = new webpackDevServer(compiler, { 28 | publicPath: config.dev.assetsPublicPath, 29 | disableHostCheck: true, 30 | hot: true, 31 | stats: { 32 | colors: true, 33 | modules: false, 34 | children: false, 35 | chunks: false, 36 | chunkModules: false 37 | }, 38 | }); 39 | 40 | console.log('> Starting dev server...'); 41 | server.listen(port, '0.0.0.0', () => { 42 | console.log(`> Listening at ${uri}\n`); 43 | // when env is testing, don't need open it 44 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 45 | opn(uri); 46 | } 47 | _resolve(); 48 | }); 49 | 50 | module.exports = { 51 | ready: readyPromise, 52 | close: () => { 53 | server.close(); 54 | } 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /scripts/server-build-client.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')(); 2 | 3 | process.env.NODE_ENV = 'production'; 4 | 5 | const ora = require('ora'); 6 | const chalk = require('chalk'); 7 | const webpack = require('webpack'); 8 | const webpackConfig = require('../config/webpack.client.conf'); 9 | 10 | const spinner = ora('building for production...'); 11 | spinner.start(); 12 | 13 | webpack(webpackConfig, (err, stats) => { 14 | spinner.stop(); 15 | if (err) throw err; 16 | process.stdout.write(`${stats.toString({ 17 | colors: true, 18 | modules: false, 19 | children: false, 20 | chunks: false, 21 | chunkModules: false 22 | })}\n\n`); 23 | 24 | if (stats.hasErrors()) { 25 | console.log(chalk.red(' Build failed with errors.\n')); 26 | process.exit(1); 27 | } 28 | 29 | console.log(chalk.cyan(' Build complete.\n')); 30 | }); 31 | -------------------------------------------------------------------------------- /scripts/server-check-schema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 检查所有模块的配置数据是否满足配置约束 3 | * @Author: CntChen 4 | * @Date: 2018-03-23 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path'); 9 | const chalk = require('chalk'); 10 | const Validator = require('./utils-schema-validator'); 11 | 12 | console.log(chalk.cyan('Check Schema:')); 13 | 14 | const getValidatorErrors = (schema, data) => { 15 | Validator.init({ 16 | options: { 17 | required_by_default: true, 18 | no_additional_properties: true, 19 | } 20 | }, schema); 21 | return Validator.validate(data); 22 | }; 23 | 24 | const baseConfigPath = path.join(__dirname, '../', 'src', 'config', 'base-config.json'); 25 | const baseConfigSchemaPath = path.join(__dirname, '../', 'src', 'config', 'base-config-schema.json'); 26 | const baseConfigObj = require(baseConfigPath); 27 | const baseConfigSchemaObj = require(baseConfigSchemaPath); 28 | 29 | const baseConfigValidateErrors = getValidatorErrors(baseConfigSchemaObj, baseConfigObj); 30 | if (baseConfigValidateErrors.length > 0) { 31 | console.error(chalk.red(`Component ${baseConfigPath} data fail to match schema.\n`, 32 | JSON.stringify(baseConfigValidateErrors, null, 2))); 33 | throw JSON.stringify(baseConfigValidateErrors); 34 | } 35 | console.log(chalk.cyan(' Base configuration schema check success.')); 36 | 37 | 38 | const componentsDir = path.join(__dirname, '../', 'src', 'components'); 39 | const componentsPath = fs.readdirSync(componentsDir); 40 | 41 | componentsPath.forEach((componentPath) => { 42 | const schemaPath = path.join(componentsDir, componentPath, 'config', 'schema.js'); 43 | const schemaObj = require(schemaPath); 44 | const dataPath = path.join(componentsDir, componentPath, 'config', 'data.json'); 45 | const dataObj = require(dataPath); 46 | 47 | const validateErrors = getValidatorErrors(schemaObj, dataObj); 48 | if (validateErrors.length > 0) { 49 | console.error(chalk.red(`Component ${componentPath} data fail to match schema.\n`, 50 | JSON.stringify(validateErrors, null, 2))); 51 | throw JSON.stringify(validateErrors); 52 | } 53 | }); 54 | 55 | console.log(chalk.cyan(' Components schema check success.\n')); 56 | -------------------------------------------------------------------------------- /scripts/server-copy-config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Desc: 将页面组件列表和页面全局配置复制到服务端目录 3 | * @Author: CntChen 4 | * @Date: 2019-01-20 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path'); 9 | 10 | const configDir = path.join(__dirname, '../', 'server', 'config'); 11 | const dirExist = fs.existsSync(configDir); 12 | if (!dirExist) { 13 | fs.mkdirSync(configDir); 14 | } 15 | 16 | const sourceDir = path.join(__dirname, '../', 'src', 'config'); 17 | const files = fs.readdirSync(sourceDir); 18 | files.forEach((file) => { 19 | fs.copyFileSync(path.join(sourceDir, file), path.join(configDir, file)); 20 | }); 21 | -------------------------------------------------------------------------------- /scripts/server-generate-library-info.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Desc: 收集组件库中组件的描述信息、默认配置数据和配置约束 3 | * @Author: CntChen 4 | * @Date: 2018-03-23 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path'); 9 | 10 | const configDir = path.join(__dirname, '../', 'server', 'config'); 11 | const dirExist = fs.existsSync(configDir); 12 | if (!dirExist) { 13 | fs.mkdirSync(configDir); 14 | } 15 | 16 | const componentsDir = path.join(__dirname, '../', 'src', 'components'); 17 | const componentsPath = fs.readdirSync(componentsDir); 18 | 19 | const componentsInfoObj = {}; 20 | componentsPath.forEach((componentPath) => { 21 | const componentInfoPath = path.join(componentsDir, componentPath, 'package.json'); 22 | const componentInfoStr = fs.readFileSync(componentInfoPath, 'utf-8'); 23 | const componentInfoObj = JSON.parse(componentInfoStr); 24 | componentsInfoObj[componentPath] = componentInfoObj; 25 | }); 26 | const libraryComponentsInfoJson = JSON.stringify(componentsInfoObj, null, 2); 27 | const libraryComponentsInfoDist = path.join(configDir, 'components-info.json'); 28 | fs.writeFileSync(libraryComponentsInfoDist, libraryComponentsInfoJson); 29 | 30 | const defaultDataObj = {}; 31 | componentsPath.forEach((componentPath) => { 32 | const componentDefaultDataPath = path.join(componentsDir, componentPath, 'config', 'data.json'); 33 | const componentDefaultDataStr = fs.readFileSync(componentDefaultDataPath, 'utf-8'); 34 | const componentDefaultDataObj = JSON.parse(componentDefaultDataStr); 35 | defaultDataObj[componentPath] = componentDefaultDataObj; 36 | }); 37 | const dataListJson = JSON.stringify(defaultDataObj, null, 2); 38 | const dataDist = path.join(configDir, 'components-default-data.json'); 39 | fs.writeFileSync(dataDist, dataListJson); 40 | 41 | const schemaObj = {}; 42 | componentsPath.forEach((componentPath) => { 43 | const componentSchemaPath = path.join(componentsDir, componentPath, 'config', 'schema.js'); 44 | const componentSchemaObj = require(componentSchemaPath); 45 | schemaObj[componentPath] = componentSchemaObj; 46 | }); 47 | const schemaListJson = JSON.stringify(schemaObj, null, 2); 48 | const schemaDist = path.join(configDir, 'components-schema.json'); 49 | fs.writeFileSync(schemaDist, schemaListJson); 50 | -------------------------------------------------------------------------------- /scripts/server-template-archive.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 打包需要提交的组件库 3 | * @Author: CntChen 4 | * @Date: 2018-03-24 5 | */ 6 | 7 | const fs = require('fs'); 8 | const path = require('path'); 9 | const chalk = require('chalk'); 10 | const archiver = require('archiver'); 11 | 12 | const libraryName = 'pipeline-template.zip'; 13 | 14 | const outputPath = path.join(__dirname, '..', libraryName); 15 | const output = fs.createWriteStream(outputPath); 16 | 17 | const archive = archiver('zip', { 18 | zlib: { 19 | level: 9 20 | } 21 | }); 22 | 23 | output.on('close', () => { 24 | console.log(` ${archive.pointer()} total bytes`); 25 | console.log(chalk.cyan(` Archiver finalized: ${libraryName}.\n`)); 26 | }); 27 | output.on('end', () => { 28 | console.log('Data has been drained'); 29 | }); 30 | archive.on('warning', (err) => { 31 | if (err.code === 'ENOENT') { 32 | // log warning 33 | } else { 34 | // throw error 35 | throw err; 36 | } 37 | }); 38 | archive.on('error', (err) => { 39 | throw err; 40 | }); 41 | 42 | archive.pipe(output); 43 | 44 | const directoryList = [ 45 | 'build', 46 | 'config', 47 | 'server', 48 | 'src' 49 | ]; 50 | const fileList = [ 51 | '.babelrc', 52 | '.editorconfig', 53 | '.eslintignore', 54 | '.eslintrc.js', 55 | '.postcssrc.js', 56 | 'package.json', 57 | 'README.md', 58 | ]; 59 | 60 | directoryList.forEach((dirPath) => { 61 | archive.directory(path.join(__dirname, '..', dirPath), dirPath); 62 | }); 63 | fileList.forEach((filePath) => { 64 | archive.file(path.join(__dirname, '..', filePath), { name: filePath }); 65 | }); 66 | 67 | archive.finalize(); 68 | -------------------------------------------------------------------------------- /scripts/utils-schema-validator.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 提取 json-editor 的校验函数, 用于非 browser 环境的 JSON schema 校验 3 | * @Author: CntChen 4 | * @Date: 2018-04-09 5 | */ 6 | 7 | // https://github.com/jdorn/json-editor/blob/master/src/validator.js 8 | Validator = { 9 | init: function(jsoneditor,schema,options) { 10 | this.jsoneditor = jsoneditor; 11 | this.schema = schema || this.jsoneditor.schema; 12 | this.options = options || {}; 13 | this.translate = () => this.arguments; 14 | return this; 15 | }, 16 | validate: function(value) { 17 | return this._validateSchema(this.schema, value); 18 | }, 19 | _validateSchema: function(schema,value,path) { 20 | var self = this; 21 | var errors = []; 22 | var valid, i, j; 23 | var stringified = JSON.stringify(value); 24 | 25 | path = path || 'root'; 26 | 27 | // Work on a copy of the schema 28 | // schema = $extend({},this.jsoneditor.expandRefs(schema)); 29 | 30 | /* 31 | * Type Agnostic Validation 32 | */ 33 | 34 | // Version 3 `required` 35 | if(schema.required && schema.required === true) { 36 | if(typeof value === "undefined") { 37 | errors.push({ 38 | path: path, 39 | property: 'required', 40 | message: this.translate("error_notset") 41 | }); 42 | 43 | // Can't do any more validation at this point 44 | return errors; 45 | } 46 | } 47 | // Value not defined 48 | else if(typeof value === "undefined") { 49 | // If required_by_default is set, all fields are required 50 | if(this.jsoneditor.options.required_by_default) { 51 | errors.push({ 52 | path: path, 53 | property: 'required', 54 | message: this.translate("error_notset") 55 | }); 56 | } 57 | // Not required, no further validation needed 58 | else { 59 | return errors; 60 | } 61 | } 62 | 63 | // `enum` 64 | if(schema["enum"]) { 65 | valid = false; 66 | for(i=0; i{{config.text}}
5 |