├── koa-app ├── test │ └── test.js ├── app │ ├── index.js │ ├── controller │ │ └── User.js │ ├── router │ │ ├── user.js │ │ └── index.js │ ├── middleWares │ │ ├── static.js │ │ ├── index.js │ │ ├── error.js │ │ └── limitFlow.js │ ├── db │ │ └── index.js │ ├── app.js │ ├── model │ │ └── UserModel.js │ └── plugins │ │ └── http.js ├── .babelrc ├── app.config.js ├── pm2.config.js ├── package.json └── README.md ├── webpack ├── test │ ├── example.txt │ ├── functions.test.js │ ├── loader.test.js │ └── compiler.js ├── loaders │ ├── ms.js │ ├── ml-loader.js │ └── ms-plugin.js ├── src │ ├── index.js │ ├── functions.js │ └── index.css ├── .babelrc ├── package.json └── webpack.config.js ├── webpack3-basic-config ├── client │ ├── view │ │ ├── test.css │ │ ├── test-styl.styl │ │ └── index.vue │ ├── app.vue │ ├── assets │ │ ├── images │ │ │ └── logo.png │ │ └── css │ │ │ └── common.css │ ├── routes.js │ ├── index.js │ ├── config.js │ └── router.js ├── .eslintignore ├── .eslintrc.js ├── favicon.ico ├── doc │ ├── images │ │ ├── koa2.jpg │ │ └── catalog.png │ └── npm包说明.md ├── public │ └── favicon.ico ├── .babelrc ├── constants.js ├── config │ ├── utils │ │ ├── http │ │ │ ├── index.js │ │ │ └── http.js │ │ ├── staticMiddleWare.js │ │ ├── logger │ │ │ ├── koa-logger.js │ │ │ └── vue-logger.js │ │ ├── errorMiddleWare.js │ │ ├── env.js │ │ ├── setCookieMiddleWare.js │ │ ├── StringUtils.js │ │ ├── responsiveDesign.js │ │ ├── token.js │ │ ├── httpMiddleWare.js │ │ ├── spaMiddleWare.js │ │ └── proxyMiddleWare.js │ ├── index.js │ ├── postcss.conf.js │ ├── vue-loader.conf.js │ ├── webpack.config.dev.js │ ├── koa-prod-server.js │ ├── webpack.config.prod.js │ ├── koa-dev-server.js │ ├── eslintrc.conf.js │ └── webpack.config.base.js ├── server.config.js ├── app.config.js ├── index.template.ejs └── package.json ├── webpack4-basic-config ├── .eslintignore ├── src │ ├── components │ │ └── index.js │ ├── app.vue │ ├── routes.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ └── test.js │ ├── views │ │ └── business │ │ │ ├── bus-detial.vue │ │ │ ├── routes.js │ │ │ └── bus-add-edit.vue │ ├── router.js │ ├── index.js │ ├── config.js │ └── utils │ │ ├── storage │ │ └── README.md │ │ └── db │ │ └── index.js ├── README.md ├── .eslintrc.js ├── favicon.ico ├── postcss.config.js ├── config │ ├── index.js │ ├── utils │ │ ├── http │ │ │ ├── index.js │ │ │ └── http.js │ │ ├── staticMiddleWare.js │ │ ├── logger │ │ │ ├── koa-logger.js │ │ │ └── vue-logger.js │ │ ├── errorMiddleWare.js │ │ ├── env.js │ │ ├── StringUtils.js │ │ ├── responsiveDesign.js │ │ ├── token.js │ │ ├── spaMiddleWare.js │ │ └── proxyMiddleWare.js │ ├── webpack.config.dll.js │ ├── webpack.config.dev.js │ ├── webpack.config.prod.js │ ├── koa-dev-server.js │ ├── eslintrc.conf.js │ └── webpack.config.base.js ├── .babelrc ├── constants.js ├── app.config.js ├── vendors-manifest.json ├── index.template.ejs └── package.json ├── react-base-webpack ├── README.md ├── .eslintrc.js ├── client │ ├── router.js │ ├── view │ │ ├── login.js │ │ └── index.js │ ├── App.js │ ├── components │ │ └── privateRoute │ │ │ └── index.js │ ├── index.js │ └── utils │ │ └── Session.js ├── favicon.ico ├── constants.js ├── config │ ├── index.js │ ├── middle │ │ ├── staticMiddleWare.js │ │ ├── errorMiddleWare.js │ │ ├── proxyToken.js │ │ ├── spaMiddleWare.js │ │ └── proxyMiddleWare.js │ ├── logger │ │ └── koa-logger.js │ ├── http │ │ └── http.js │ ├── webpack.config.dev.js │ ├── koa.server.js │ ├── webpack.config.base.js │ ├── webpack.config.prod.js │ └── eslintrc.conf.js ├── postcss.config.js ├── app.config.js ├── .babelrc ├── index.template.ejs └── package.json ├── webpack4-ssr-config ├── .eslintrc.js ├── client │ ├── app.vue │ ├── assets │ │ ├── images │ │ │ ├── 01.jpg │ │ │ └── logo.png │ │ └── css │ │ │ └── reset.css │ ├── plugins │ │ └── index.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ └── test.js │ ├── views │ │ ├── test │ │ │ ├── routes.js │ │ │ ├── data.vue │ │ │ └── ajax.vue │ │ └── home.vue │ ├── routes.js │ ├── router.js │ ├── utils │ │ └── title.js │ ├── index.js │ ├── config.js │ ├── entry-client.js │ ├── entry-server.js │ └── components │ │ └── ProgressBar.vue ├── favicon.ico ├── dist │ └── favicon.ico ├── config │ ├── index.js │ ├── http │ │ ├── index.js │ │ └── http.js │ ├── middle │ │ ├── staticMiddleWare.js │ │ ├── errorMiddleWare.js │ │ └── proxyMiddleWare.js │ ├── logger │ │ ├── koa-logger.js │ │ └── vue-logger.js │ ├── webpack.client.config.js │ ├── koa.server.js │ ├── webpack.server.config.js │ ├── vue.koa.ssr.js │ ├── setup.dev.server.js │ └── eslintrc.conf.js ├── postcss.config.js ├── constants.js ├── .babelrc ├── app.config.js ├── pm2.config.js ├── index.template.ejs ├── package.json └── pm2.md ├── .gitignore └── README.md /koa-app/test/test.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /webpack/test/example.txt: -------------------------------------------------------------------------------- 1 | Hey [name]! 2 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/view/test.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webpack/loaders/ms.js: -------------------------------------------------------------------------------- 1 | console.log('这里是ms') 2 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/view/test-styl.styl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webpack3-basic-config/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_module/* 2 | /config/* -------------------------------------------------------------------------------- /webpack4-basic-config/.eslintignore: -------------------------------------------------------------------------------- 1 | /node_module/* 2 | /config/* -------------------------------------------------------------------------------- /webpack4-basic-config/src/components/index.js: -------------------------------------------------------------------------------- 1 | export default [] -------------------------------------------------------------------------------- /react-base-webpack/README.md: -------------------------------------------------------------------------------- 1 | # Webpack4 + React + Koa2 构建spa应用 2 | -------------------------------------------------------------------------------- /webpack4-basic-config/README.md: -------------------------------------------------------------------------------- 1 | # Webpack4 + Vue2 + Koa2 构建spa应用 2 | -------------------------------------------------------------------------------- /webpack/src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | 3 | console.log('hello world') 4 | -------------------------------------------------------------------------------- /react-base-webpack/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/eslintrc.conf.js') -------------------------------------------------------------------------------- /react-base-webpack/client/router.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 18/11/1. 3 | */ -------------------------------------------------------------------------------- /webpack3-basic-config/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/eslintrc.conf.js') -------------------------------------------------------------------------------- /webpack4-basic-config/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/eslintrc.conf.js') -------------------------------------------------------------------------------- /webpack4-ssr-config/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/eslintrc.conf.js') -------------------------------------------------------------------------------- /webpack4-basic-config/src/app.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /webpack/src/functions.js: -------------------------------------------------------------------------------- 1 | export default { 2 | sum(a, b) { 3 | return a + b; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/app.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/app.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /koa-app/app/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * app入口文件 3 | */ 4 | require('@babel/register') 5 | require('./app.js') 6 | -------------------------------------------------------------------------------- /react-base-webpack/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/react-base-webpack/favicon.ico -------------------------------------------------------------------------------- /webpack4-ssr-config/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack4-ssr-config/favicon.ico -------------------------------------------------------------------------------- /webpack3-basic-config/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack3-basic-config/favicon.ico -------------------------------------------------------------------------------- /webpack4-basic-config/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack4-basic-config/favicon.ico -------------------------------------------------------------------------------- /webpack4-ssr-config/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack4-ssr-config/dist/favicon.ico -------------------------------------------------------------------------------- /webpack4-basic-config/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'autoprefixer': { browsers: '> 0.1%' }, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /webpack3-basic-config/doc/images/koa2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack3-basic-config/doc/images/koa2.jpg -------------------------------------------------------------------------------- /webpack3-basic-config/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack3-basic-config/public/favicon.ico -------------------------------------------------------------------------------- /react-base-webpack/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | module.exports = { 5 | proxy: { 6 | '/api': 'http://restapi.amap.com', 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /webpack/src/index.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | color: #3a8ee6 7 | } 8 | -------------------------------------------------------------------------------- /webpack3-basic-config/doc/images/catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack3-basic-config/doc/images/catalog.png -------------------------------------------------------------------------------- /webpack4-ssr-config/client/assets/images/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack4-ssr-config/client/assets/images/01.jpg -------------------------------------------------------------------------------- /webpack4-ssr-config/client/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack4-ssr-config/client/assets/images/logo.png -------------------------------------------------------------------------------- /webpack/test/functions.test.js: -------------------------------------------------------------------------------- 1 | import functions from '../src/functions' 2 | 3 | test('sum(2 + 2) 等于 4', () => { 4 | expect(functions.sum(2, 2)).toBe(4) 5 | }) 6 | -------------------------------------------------------------------------------- /webpack3-basic-config/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env" 4 | ], 5 | "plugins": [ 6 | "transform-vue-jsx", 7 | "syntax-dynamic-import" 8 | ] 9 | } -------------------------------------------------------------------------------- /webpack3-basic-config/client/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zdliuccit/vue-webpack-config/HEAD/webpack3-basic-config/client/assets/images/logo.png -------------------------------------------------------------------------------- /webpack4-ssr-config/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliu on 2018/7/6. 3 | * * app入口,使整个应用基于es6开发 4 | */ 5 | require('@babel/polyfill') 6 | require('./koa.server') 7 | -------------------------------------------------------------------------------- /react-base-webpack/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2018/11/1. 3 | * * app入口,使整个应用基于es6开发 4 | */ 5 | require('@babel/polyfill') 6 | require('./koa.server') 7 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/6. 3 | * * app入口,使整个应用基于es6开发 4 | */ 5 | require('@babel/polyfill') 6 | require('./koa-dev-server') 7 | -------------------------------------------------------------------------------- /webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "node": "4" 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # dependencies 3 | **/node_modules 4 | # roadhog-api-doc ignore 5 | /src/utils/request-temp.js 6 | _roadhog-api-doc 7 | 8 | # production 9 | */.vscode 10 | .idea 11 | */.idea 12 | -------------------------------------------------------------------------------- /koa-app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /react-base-webpack/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'autoprefixer': { browsers: '> 0.1%' }, 4 | // 'postcss-pxtorem': { rootValue: 100, propWhiteList: [], replace: true, }, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /webpack4-ssr-config/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'autoprefixer': { browsers: '> 0.1%' }, 4 | // 'postcss-pxtorem': { rootValue: 100, propWhiteList: [], replace: true, }, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /webpack4-ssr-config/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | module.exports = { 5 | proxy: { 6 | '/api': 'http://restapi.amap.com/', 7 | }, 8 | prodProxy: { 9 | '/api': 'http://restapi.amap.com/', 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /webpack4-ssr-config/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "transform-vue-jsx", 7 | "@babel/plugin-syntax-jsx", 8 | "@babel/plugin-syntax-dynamic-import" 9 | ] 10 | } -------------------------------------------------------------------------------- /webpack3-basic-config/client/routes.js: -------------------------------------------------------------------------------- 1 | import main from './view/index.vue' 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | component: main, 7 | meta: { title: '首页' } 8 | }, 9 | ] 10 | 11 | export default routes 12 | -------------------------------------------------------------------------------- /webpack4-basic-config/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "transform-vue-jsx", 7 | "@babel/plugin-syntax-jsx", 8 | "@babel/plugin-syntax-dynamic-import" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /react-base-webpack/client/view/login.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | class Login extends React.Component { 4 | render() { 5 | return ( 6 |
7 | 登陆页面 8 |
9 | ) 10 | } 11 | } 12 | 13 | export default Login -------------------------------------------------------------------------------- /koa-app/app/controller/User.js: -------------------------------------------------------------------------------- 1 | class User { 2 | 3 | async login(ctx) { 4 | ctx.body = '' 5 | } 6 | 7 | async signOut(ctx) { 8 | } 9 | 10 | async register(ctx) { 11 | ctx.body = '' 12 | } 13 | } 14 | 15 | export default new User() 16 | -------------------------------------------------------------------------------- /webpack4-basic-config/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/6. 3 | */ 4 | /** 5 | * 本文件仅用于本地开发环境,用于存放一些常量 6 | */ 7 | module.exports = { 8 | // 代理 9 | proxy: { 10 | '/v3/assistant': 'http://restapi.amap.com/v3/', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/plugins/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import 'quill/dist/quill.core.css' 3 | import 'quill/dist/quill.snow.css' 4 | import 'quill/dist/quill.bubble.css' 5 | 6 | if (process.browser) { 7 | Vue.use(require('vue-quill-editor/dist/ssr')) 8 | } -------------------------------------------------------------------------------- /webpack4-basic-config/src/routes.js: -------------------------------------------------------------------------------- 1 | import businessRoute from './views/business/routes' 2 | import empty from './app.vue' 3 | 4 | const routes = [ 5 | { 6 | path: '/', 7 | component: empty, 8 | children: businessRoute 9 | }, 10 | ] 11 | 12 | export default routes 13 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import test from './modules/test' 4 | 5 | Vue.use(Vuex) 6 | 7 | export function createStore() { 8 | return new Vuex.Store({ 9 | modules: { 10 | test 11 | } 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import test from './modules/test' 4 | 5 | Vue.use(Vuex) 6 | 7 | export function createStore() { 8 | return new Vuex.Store({ 9 | modules: { 10 | test 11 | } 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /webpack3-basic-config/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/6. 3 | */ 4 | /** 5 | * 本文件仅用于本地开发环境,用于存放一些常量 6 | */ 7 | module.exports = { 8 | // 登陆 9 | loginTargets: { 10 | dev: 'http://shop.dev.so:8080', 11 | test: 'http://shop.test.so:8080', 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/views/test/routes.js: -------------------------------------------------------------------------------- 1 | const data = () => import('./data.vue') 2 | const ajax = () => import('./ajax.vue') 3 | 4 | export default [ 5 | { 6 | path: 'data', 7 | component: data, 8 | }, 9 | { 10 | path: 'ajax', 11 | component: ajax, 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/http/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 为vue实例添加http方法 3 | * Vue.use(http) 4 | */ 5 | import http from './http' 6 | 7 | export default { 8 | /** 9 | * install钩子 10 | * @param {Vue} Vue Vue 11 | */ 12 | install(Vue) { 13 | Vue.prototype.http = http 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/http/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 为vue实例添加http方法 3 | * Vue.use(http) 4 | */ 5 | import http from './http' 6 | 7 | export default { 8 | /** 9 | * install钩子 10 | * @param {Vue} Vue Vue 11 | */ 12 | install(Vue) { 13 | Vue.prototype.http = http 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /koa-app/app/router/user.js: -------------------------------------------------------------------------------- 1 | import UserController from '../controller/User' 2 | import Router from 'koa-router' 3 | 4 | const User = new Router(); 5 | 6 | User.get('/login', UserController.login); 7 | User.get('/signOut', UserController.signOut); 8 | User.get('/register', UserController.register); 9 | 10 | export default User 11 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/6. 3 | * * app入口,使整个应用基于es6开发 4 | */ 5 | require('babel-core/register') 6 | require('babel-polyfill') 7 | if (process.env.NODE_ENV === 'development') { 8 | require('./koa-dev-server') 9 | } else { 10 | require('./koa-prod-server') 11 | } 12 | -------------------------------------------------------------------------------- /webpack3-basic-config/server.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 配置服务端口,以及代理 3 | */ 4 | const constants = require('./constants') 5 | const common = 'test' 6 | module.exports = { 7 | appPort: 9009, 8 | proxy: { 9 | '/api/test': constants.loginTargets[common], 10 | '/v3/assistant': 'http://restapi.amap.com/v3/', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /koa-app/app/middleWares/static.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置静态资源请求目录和设置缓存 3 | * @return {Promise.} 4 | */ 5 | import serverStatic from 'koa-static' 6 | 7 | const path = require('path') 8 | 9 | export default () => { 10 | return serverStatic(path.join(process.cwd(), 'app/public'), { maxAge: 60 * 60 * 24 * 30 * 1000, gzip: true }) 11 | } 12 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/http/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/6. 3 | * 为vue实例添加http方法 4 | * Vue.use(http) 5 | */ 6 | import http from './http' 7 | 8 | export default { 9 | /** 10 | * install钩子 11 | * @param {Vue} Vue Vue 12 | */ 13 | install(Vue) { 14 | Vue.prototype.$http = http 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /webpack/test/loader.test.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | import compiler from './compiler.js'; 3 | 4 | test('Inserts name and outputs JavaScript', async () => { 5 | const stats = await compiler('example.txt'); 6 | const output = stats.toJson().modules[0].source; 7 | 8 | // expect(output).toBe('export default "Hey Alice!\\n"'); 9 | }); 10 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/middle/staticMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置静态资源请求目录和设置缓存 3 | * @return {Promise.} 4 | */ 5 | const path = require('path') 6 | const serverStatic = require("koa-static") 7 | 8 | module.exports = function () { 9 | return serverStatic(path.resolve(process.cwd()), { maxAge: 30 * 24 * 60 * 60 * 1000, gzip: true }) 10 | } -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/staticMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置静态资源请求目录和设置缓存 3 | * @return {Promise.} 4 | */ 5 | const path = require('path') 6 | const serverStatic = require("koa-static") 7 | 8 | module.exports = function () { 9 | return serverStatic(path.join(process.cwd(), 'public'), { maxAge: 30 * 24 * 60 * 60 * 1000, gzip: true }) 10 | } -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/staticMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置静态资源请求目录和设置缓存 3 | * @return {Promise.} 4 | */ 5 | const path = require('path') 6 | const serverStatic = require("koa-static") 7 | 8 | module.exports = function () { 9 | return serverStatic(path.join(process.cwd(), 'dist'), {maxAge: 30 * 24 * 60 * 60 * 1000, gzip: true}) 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webpack、Vue、React、Koa2 2 | 3 | ### React 4 | 5 | * [基于webpack4、koa2的react基础配置脚手架](react-base-webpack) 6 | 7 | ### Vue 8 | 9 | * [基于webpack3、koa2的vue的基础配置脚手架](webpack3-basic-config) 10 | * [基于webpack4、koa2的vue的基础配置脚手架](webpack4-basic-config) 11 | * [基于webpack4、koa2的vue的SSR配置脚手架](webpack4-ssr-config) 12 | 13 | 14 | ### Node 15 | 16 | * [koa服务端](koa-app) 17 | -------------------------------------------------------------------------------- /react-base-webpack/config/middle/staticMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2018/11/1. 3 | * 设置静态资源请求目录和设置缓存 4 | * @return {Promise.} 5 | */ 6 | const path = require('path') 7 | const serverStatic = require("koa-static") 8 | 9 | module.exports = function () { 10 | return serverStatic(path.resolve(process.cwd()), { maxAge: 30 * 24 * 60 * 60 * 1000, gzip: true }) 11 | } -------------------------------------------------------------------------------- /webpack4-ssr-config/client/routes.js: -------------------------------------------------------------------------------- 1 | import testRoutes from './views/test/routes' 2 | import entry from './app.vue' 3 | 4 | const home = () => import('./views/home.vue') 5 | const routes = [ 6 | { 7 | path: '/', 8 | component: home 9 | }, 10 | { 11 | path: '/test', 12 | component: entry, 13 | children: testRoutes 14 | }, 15 | ] 16 | 17 | export default routes 18 | -------------------------------------------------------------------------------- /react-base-webpack/config/logger/koa-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/22. 3 | * log模块,依赖winston 4 | */ 5 | 6 | const winston = require('winston') 7 | 8 | module.exports = function (filename) { 9 | return winston.loggers.get(filename, { 10 | console: { 11 | level: 'info', // 定死这个级别,只允许使用debug,warn,error三个方法 12 | colorize: true, 13 | label: filename, 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/logger/koa-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/22. 3 | * log模块,依赖winston 4 | */ 5 | 6 | const winston = require('winston') 7 | 8 | module.exports = function (filename) { 9 | return winston.loggers.get(filename, { 10 | console: { 11 | level: 'info', // 定死这个级别,只允许使用debug,warn,error三个方法 12 | colorize: true, 13 | label: filename, 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/logger/koa-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/22. 3 | * log模块,依赖winston 4 | */ 5 | 6 | const winston = require('winston') 7 | 8 | module.exports = function (filename) { 9 | return winston.loggers.get(filename, { 10 | console: { 11 | level: 'info', // 定死这个级别,只允许使用debug,warn,error三个方法 12 | colorize: true, 13 | label: filename, 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/logger/koa-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/22. 3 | * log模块,依赖winston 4 | */ 5 | 6 | const winston = require('winston') 7 | 8 | module.exports = function (filename) { 9 | return winston.loggers.get(filename, { 10 | console: { 11 | level: 'info', // 定死这个级别,只允许使用debug,warn,error三个方法 12 | colorize: true, 13 | label: filename, 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | // 引入响应式设计JS 3 | import '@config/utils/responsiveDesign' 4 | // 第三方库 5 | import Vue from 'vue' 6 | // reset样式 7 | import '@/assets/css/common.css' 8 | // vue config配置文件 9 | import './config' 10 | // 自己实现的方法 11 | import router from './router' 12 | import App from './app.vue' 13 | 14 | /*eslint-disable*/ 15 | new Vue({ 16 | el: '#app', 17 | router, 18 | // store, 19 | render: h => h(App) 20 | }) 21 | -------------------------------------------------------------------------------- /react-base-webpack/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目的一些定制化配置 3 | */ 4 | const path = require('path') 5 | const constants = require('./constants') 6 | 7 | module.exports = { 8 | // 主服务启动端口 9 | appPort: 8088, 10 | // 代理配置,可支持多个代理,key为前缀,命中后,会把前缀去掉,转发到代理服务器 11 | proxy: constants.proxy, 12 | // webpack的差异化配置 13 | webpack: { 14 | entry: { 15 | app: path.join(__dirname, 'client/index.js') // 入口 16 | }, 17 | }, 18 | // 自定义中间件 async await函数写法 19 | middleWares: [] 20 | } 21 | -------------------------------------------------------------------------------- /koa-app/app/router/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 模块化处理router 3 | */ 4 | import Router from 'koa-router' 5 | import User from './user' 6 | 7 | const router = new Router() 8 | 9 | /** 10 | * 启动路由 11 | * allowedMethods,在当所有路由中间件最后调用.此时根据 ctx.status 设置 response 响应头 12 | */ 13 | export default (app) => { 14 | router.get('/', async ctx => { 15 | ctx.body = 'ml-app' 16 | }) 17 | router.use('/user', User.routes(), User.allowedMethods()) 18 | app.use(router.routes(), router.allowedMethods()) 19 | } 20 | -------------------------------------------------------------------------------- /koa-app/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 配置文件 3 | */ 4 | export default { 5 | appPort: 7878, 6 | db: { 7 | url: 'mongodb://localhost:27017/ml', 8 | }, 9 | secret: 'zdliuccit', 10 | /** 11 | * 限流中间件配置,令牌桶(Token bucket) 12 | * @desc 限流三种算法 令牌桶(Token bucket) 漏桶(Leaky bucket) 计数器(Counter) 13 | * enable # 状态 14 | * rate # 令牌桶模式 令牌加入桶的速率 15 | * upperLimit # 上限 16 | * */ 17 | currentLimitedConfig: { 18 | enable: true, 19 | rate: 100, 20 | upperLimit: 1000 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /koa-app/app/middleWares/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 中间件集合 3 | */ 4 | import staticMiddleWares from './static' 5 | import limitFlowMiddleWares from './limitFlow' 6 | import errorMiddleWare from './error' 7 | 8 | /** 9 | * 中间件,一组async函数,generator函数需要convert转换 10 | */ 11 | export default (app) => { 12 | const middleWares = [ 13 | errorMiddleWare, 14 | staticMiddleWares(), 15 | limitFlowMiddleWares() 16 | ] 17 | middleWares.forEach((middleware) => { 18 | app.use(middleware) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /react-base-webpack/client/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PrivateRoute from './components/privateRoute' 3 | import { Route, Switch } from 'react-router-dom' 4 | import Login from './view/login' 5 | import Index from './view/index' 6 | 7 | class App extends React.Component { 8 | render() { 9 | return ( 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | } 17 | 18 | export default App 19 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/errorMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/7. 3 | * 错误处理中间件 4 | * @param {ctx} ctx koa ctx 5 | * @param {Function} next koa next */ 6 | 7 | module.exports = async function (ctx, next) { 8 | try { 9 | // Node标识 10 | ctx.set('X-Proxy', 'Node Server') 11 | await next() 12 | } catch (err) { 13 | ctx.status = err.status || 500 14 | ctx.body = 'We are sorry. Internal server error occurred.' 15 | ctx.app.emit('error', err, ctx) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/errorMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/7. 3 | * 错误处理中间件 4 | * @param {ctx} ctx koa ctx 5 | * @param {Function} next koa next */ 6 | 7 | module.exports = async function (ctx, next) { 8 | try { 9 | // Node标识 10 | ctx.set('X-Proxy', 'Node Server') 11 | await next() 12 | } catch (err) { 13 | ctx.status = err.status || 500 14 | ctx.body = 'We are sorry. Internal server error occurred.' 15 | ctx.app.emit('error', err, ctx) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /webpack4-ssr-config/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目的一些定制化配置 3 | */ 4 | const path = require('path') 5 | const constants = require('./constants') 6 | const isProd = process.env.NODE_ENV === 'production' 7 | 8 | module.exports = { 9 | // 主服务启动端口 10 | appPort: 8098, 11 | // 代理配置,可支持多个代理,key为前缀,命中后,会把前缀去掉,转发到代理服务器 12 | proxy: isProd ? constants.prodProxy : constants.proxy, 13 | // webpack的差异化配置 14 | webpack: { 15 | entry: { 16 | app: path.join(__dirname, 'client/index.js'), // 入口 17 | }, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /koa-app/app/middleWares/error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/7. 3 | * 错误处理中间件,放在所以中间价之前,就可以捕获它们所有的同步或者异步代码中抛出的异常 4 | * @param ctx koa ctx 5 | * @param next koa next */ 6 | 7 | export default async (ctx, next) => { 8 | try { 9 | // Node标识 10 | ctx.set('X-Proxy', 'Node Server') 11 | await next() 12 | } catch (err) { 13 | console.log('err', err) 14 | ctx.status = err.status || 500 15 | ctx.body = 'We are sorry. Internal server error occurred.' 16 | ctx.app.emit('error', err, ctx) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/7. 3 | * 各种环境变量 4 | */ 5 | module.exports = { 6 | // 是否服务端渲染模式 7 | IS_SSR: process.env.RENDER_MODE === 'server', 8 | // 是否开发环境 9 | IS_DEBUG: process.env.NODE_ENV === 'development', 10 | // 是否生产环境,不能根据process.env.NODE_ENV === 'production'来判断 11 | // 我们设置所有服务器集成部署方式都是process.env.NODE_ENV === 'production' 12 | // SERVER_ENV是与运维约定的一个环境变量,表示服务器环境,值可能为dev,test,pre,product 13 | IS_SERVER_PRODUCTION: process.env.SERVER_ENV === 'production', 14 | } 15 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/7. 3 | * 各种环境变量 4 | */ 5 | module.exports = { 6 | // 是否服务端渲染模式 7 | IS_SSR: process.env.RENDER_MODE === 'server', 8 | // 是否开发环境 9 | IS_DEBUG: process.env.NODE_ENV === 'development', 10 | // 是否生产环境,不能根据process.env.NODE_ENV === 'production'来判断 11 | // 我们设置所有服务器集成部署方式都是process.env.NODE_ENV === 'production' 12 | // SERVER_ENV是与运维约定的一个环境变量,表示服务器环境,值可能为dev,test,pre,product 13 | IS_SERVER_PRODUCTION: process.env.SERVER_ENV === 'production', 14 | } 15 | -------------------------------------------------------------------------------- /react-base-webpack/client/components/privateRoute/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route, Redirect, } from 'react-router-dom' 3 | import { isAuthenticated } from './../../utils/Session' 4 | 5 | const PrivateRoute = ({ component: Component, ...rest }) => ( 6 | ( 7 | !!isAuthenticated() 8 | ? 9 | : 13 | )}/> 14 | ) 15 | 16 | export default PrivateRoute -------------------------------------------------------------------------------- /react-base-webpack/config/middle/errorMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2018/11/1. 3 | * 错误处理中间件,放在所以中间价之前,就可以捕获它们所有的同步或者异步代码中抛出的异常 4 | * @param {ctx} ctx koa ctx 5 | * @param {Function} next koa next */ 6 | 7 | module.exports = async function (ctx, next) { 8 | try { 9 | // Node标识 10 | ctx.set('X-Proxy', 'Node Server') 11 | await next() 12 | } catch (err) { 13 | ctx.status = err.status || 500 14 | ctx.body = 'We are sorry. Internal server error occurred.' 15 | ctx.app.emit('error', err, ctx) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/middle/errorMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/7. 3 | * 错误处理中间件,放在所以中间价之前,就可以捕获它们所有的同步或者异步代码中抛出的异常 4 | * @param {ctx} ctx koa ctx 5 | * @param {Function} next koa next */ 6 | 7 | module.exports = async function (ctx, next) { 8 | try { 9 | // Node标识 10 | ctx.set('X-Proxy', 'Node Server') 11 | await next() 12 | } catch (err) { 13 | ctx.status = err.status || 500 14 | ctx.body = 'We are sorry. Internal server error occurred.' 15 | ctx.app.emit('error', err, ctx) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /react-base-webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | [ 9 | "import", 10 | { 11 | "libraryName": "antd", 12 | "libraryDirectory": "es", 13 | "style": "css" 14 | // `style: true` 会加载 less 文件 15 | } 16 | ] 17 | // ["@babel/plugin-proposal-decorators", { "legacy": true }], 18 | // ["@babel/plugin-proposal-class-properties", { "loose": true }], 19 | ] 20 | } -------------------------------------------------------------------------------- /webpack4-basic-config/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目的一些定制化配置 3 | */ 4 | const path = require('path') 5 | const constants = require('./constants') 6 | 7 | module.exports = { 8 | // 主服务启动端口 9 | appPort: 8686, 10 | // 代理配置,可支持多个代理,key为前缀,命中后,会把前缀去掉,转发到代理服务器 11 | proxy: constants.proxy, 12 | // 可以添加第三方包,加快打包速度和加载, webpack.DllPlugin 13 | webpackDLL: [], 14 | // webpack的差异化配置 15 | webpack: { 16 | entry: { 17 | app: path.join(__dirname, 'src/index.js'), 18 | }, 19 | }, 20 | // 自定义中间件 async await函数写法 21 | middleWares: [] 22 | } 23 | -------------------------------------------------------------------------------- /koa-app/pm2.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [{ 3 | name: 'ml-app', // app名称 4 | script: 'app/index.js', // 要运行的脚本的路径。 5 | args: '', // 由传递给脚本的参数组成的字符串或字符串数​​组。 6 | output: './log/out.log', 7 | error: './log/error.log', 8 | log: './log/combined.outerr.log', 9 | merge_logs: true, // 集群的所有实例的日志文件合并 10 | log_date_format: "DD-MM-YYYY", 11 | instances: 4, // 进程数 1、数字 2、'max'根据cpu内核数 12 | max_memory_restart: '1G', // 当内存超过1024M时自动重启 13 | watching: true, 14 | env_production: { 15 | NODE_ENV: 'production' 16 | } 17 | }], 18 | } 19 | -------------------------------------------------------------------------------- /react-base-webpack/client/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 18/11/1. 3 | */ 4 | import '@babel/polyfill' 5 | import React from 'react' 6 | import ReactDOM from 'react-dom' 7 | import App from './App' 8 | import { BrowserRouter as Router } from 'react-router-dom' 9 | import { LocaleProvider } from 'antd' 10 | import zh_CN from 'antd/lib/locale-provider/zh_CN' 11 | 12 | ReactDOM.render( 13 | 14 | 15 | 16 | 17 | , 18 | document.getElementById('app') 19 | ) 20 | 21 | if (module.hot) { 22 | module.hot.accept() 23 | } -------------------------------------------------------------------------------- /webpack4-ssr-config/client/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import routes from './routes' 4 | 5 | Vue.use(Router) 6 | 7 | export function createRouter() { 8 | const router = new Router({ 9 | mode: 'history', 10 | fallback: false, 11 | // base: '/ssr', 12 | routes 13 | }) 14 | 15 | router.beforeEach((to, from, next) => { 16 | /*todo 17 | * 做权限验证的时候,服务端和客户端状态同步的时候会执行一次 18 | * 建议vuex里用一个状态值控制,默认false,同步时直接next,因为服务端已经执行过。 19 | * */ 20 | next() 21 | }) 22 | 23 | router.afterEach((route) => { 24 | /*todo*/ 25 | }) 26 | return router 27 | } -------------------------------------------------------------------------------- /koa-app/app/db/index.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose' 2 | import UserModel from './../model/UserModel' 3 | import appConfig from './../../app.config' 4 | 5 | const NODE_ENV = process.env.NODE_ENV 6 | 7 | mongoose.connect( 8 | appConfig.db.url, 9 | { 10 | useNewUrlParser: true, 11 | bufferCommands: false, 12 | autoIndex: NODE_ENV === 'development' 13 | } 14 | ); 15 | 16 | const db = mongoose.connection; 17 | 18 | db.on('error', console.error.bind(console, 'connection error:')); 19 | db.once('open', function () { 20 | console.log('db connect success'); 21 | }); 22 | 23 | export default { 24 | UserModel, 25 | } 26 | -------------------------------------------------------------------------------- /webpack4-ssr-config/pm2.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [{ 3 | name: 'ml-app', // app名称 4 | script: 'config/index.js', // 要运行的脚本的路径。 5 | args: '', // 由传递给脚本的参数组成的字符串或字符串数​​组。 6 | output: './log/out.log', 7 | error: './log/error.log', 8 | log: './log/combined.outerr.log', 9 | merge_logs: true, // 集群的所有实例的日志文件合并 10 | log_date_format: "DD-MM-YYYY", 11 | instances: 4, // 进程数 1、数字 2、'max'根据cpu内核数 12 | max_memory_restart: '1G', // 当内存超过1024M时自动重启 13 | watching: true, 14 | env_test: { 15 | NODE_ENV: 'production' 16 | }, 17 | env_production: { 18 | NODE_ENV: 'production' 19 | } 20 | }], 21 | } 22 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/utils/title.js: -------------------------------------------------------------------------------- 1 | function getTitle(vm) { 2 | const { title } = vm.$options 3 | if (title) { 4 | return typeof title === 'function' ? title.call(vm) : title 5 | } 6 | } 7 | 8 | /** 9 | * 生产环境 server处理 10 | */ 11 | const serverTitleMixin = { 12 | created() { 13 | const title = getTitle(this) 14 | if (title) this.$ssrContext.title = title || 'Vue Koa2 SSR' 15 | } 16 | } 17 | 18 | /** 19 | * 开发环境 正常处理 20 | */ 21 | const clientTitleMixin = { 22 | mounted() { 23 | const title = getTitle(this) 24 | if (title) document.title = title || 'Vue Koa2 SSR' 25 | } 26 | } 27 | 28 | export default process.env.VUE_ENV === 'server' ? serverTitleMixin : clientTitleMixin 29 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/setCookieMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 生产环境屏蔽 3 | * 黑科技----手动在浏览器地址栏输入url,达到设置cookie的效果 4 | * 比如在页面上输入 http://192.168.144.64:8023/set-cookie?name=aaa&value=111 5 | * 将会写入key为aaa值为111的cookie到浏览器中 6 | * @param {Object} ctx koa ctx 7 | * @param {Function} next koa next 8 | * @return {Promise} promise 9 | */ 10 | // eslint-disable-next-line consistent-return 11 | module.exports = async function (ctx, next) { 12 | if (ctx.path !== '/set-cookie') { 13 | return next() 14 | } 15 | const params = ctx.query 16 | ctx.set('Set-Cookie', `${params.name}=${params.value}; Path=/; HttpOnly`) 17 | ctx.body = `Cookie '${params.name}' has been successfully set to '${params.value}'!` 18 | } 19 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/postcss.conf.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer') 2 | const pxtorem = require('postcss-pxtorem') 3 | const webpackAppConfig = require('./../app.config').webpack 4 | /** 5 | * postcss 添加浏览器前缀插件 6 | * @return [] 7 | */ 8 | module.exports = function () { 9 | const posts = [ 10 | // 添加浏览器前缀 解决兼容问题 11 | autoprefixer({ browsers: webpackAppConfig.browsers || '> 0.1%', }), 12 | ] 13 | // 是否对样式启用px到rem的转换, 默认不开启 14 | if (webpackAppConfig.enablePx2Rem) { 15 | const pxtoremOptions = Object.assign({}, { 16 | rootValue: 100, 17 | propWhiteList: [], 18 | replace: true, 19 | }) 20 | posts.push(pxtorem(pxtoremOptions)) 21 | } 22 | // 合并项目设置的插件 23 | return posts.concat(webpackAppConfig.postcss || []) 24 | } 25 | -------------------------------------------------------------------------------- /koa-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ml", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app/index.js", 6 | "scripts": { 7 | "start": "nodemon app/index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "app": "pm2 start pm2.config.js --env production" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@babel/core": "7.11.5", 15 | "@babel/preset-env": "7.11.5", 16 | "@babel/register": "7.11.5", 17 | "axios": "0.20.0", 18 | "keygrip": "1.1.0", 19 | "koa": "2.13.0", 20 | "koa-compress": "5.0.1", 21 | "koa-logger": "3.2.1", 22 | "koa-router": "9.4.0", 23 | "koa-session": "6.0.0", 24 | "koa-static": "5.0.0", 25 | "mongoose": "5.10.4", 26 | "nodemon": "2.0.4" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/webpack.config.dll.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack dll 配置 分离第三方库 加速打包和 有利于缓存 3 | * Created by liuzhengdong on 2018/4/12. 4 | */ 5 | const webpack = require('webpack'); 6 | const path = require('path'); 7 | const appConfig = require(path.join(process.cwd(), 'app.config')) 8 | 9 | const vendors = ['vue', 'vuex', 'vue-router']; 10 | module.exports = { 11 | mode: 'production', 12 | output: { 13 | filename: '[name]_[chunkhash:8].dll.js', 14 | library: '[name]_[chunkhash:8]', 15 | }, 16 | entry: { 17 | 'vendors': vendors.concat(appConfig.webpackDLL || []), 18 | }, 19 | plugins: [ 20 | new webpack.DllPlugin({ 21 | name: '[name]_[chunkhash:8]', 22 | context: path.join(process.cwd()), 23 | path: path.join(process.cwd(), '[name]-manifest.json'), 24 | }), 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/index.js: -------------------------------------------------------------------------------- 1 | import '@babel/polyfill' 2 | import Vue from 'vue' 3 | import App from './app.vue' 4 | import { createStore } from './store' 5 | import { createRouter } from './router' 6 | import { sync } from 'vuex-router-sync' 7 | 8 | // reset 样式 9 | import './assets/css/reset.css' 10 | 11 | // config配置文件 12 | import './config' 13 | // 涉及到原生对象调用的插件统一放plugins目录下 14 | import './plugins' 15 | // 导出一个工厂函数,用于创建新的 16 | // 应用程序、router 和 store 实例 17 | export function createApp() { 18 | // 创建 router 实例 19 | const router = createRouter() 20 | // 创建 store 实力 21 | const store = createStore() 22 | 23 | // sync the router with the vuex store. 24 | sync(store, router) 25 | 26 | const app = new Vue({ 27 | // 注入 router 到根 Vue 实例 28 | router, 29 | store, 30 | render: h => h(App) 31 | }) 32 | return { app, router, store } 33 | } -------------------------------------------------------------------------------- /webpack3-basic-config/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目的一些定制化配置 3 | */ 4 | const path = require('path') 5 | const serverConfig = require('./server.config') 6 | 7 | module.exports = { 8 | // 主服务启动端口 9 | appPort: serverConfig.appPort, 10 | // 代理配置,可支持多个代理,key为前缀,命中后,会把前缀去掉,转发到代理服务器 11 | proxy: serverConfig.proxy, 12 | // webpack的差异化配置 13 | webpack: { 14 | entry: { 15 | app: path.join(__dirname, 'client/index.js'), // 入口 16 | vendor: ['vue', 'vue-router'] // 拆分框架代码 17 | }, 18 | // 是否对样式启用px到rem的转换,配合config/utils/responsive-design.js适配移动端开发, 默认不开启 19 | enablePx2Rem: false, 20 | // 自定义Alias设置 21 | resolveAlias: {}, 22 | // 扩展rules 23 | rules: [], 24 | // 扩展css postcss 25 | postcss: [], 26 | // 定义 autoprefixer 兼容 默认内部配置为 >0.1% 27 | browsers: '' 28 | }, 29 | // 自定义中间件 async await函数写法 30 | middleWares: [] 31 | } 32 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/StringUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/22. 3 | * 存放公共方法 4 | */ 5 | module.exports = { 6 | /** 7 | * 函数节流 8 | * @param fn 函数 9 | * @param delay 多久执行一次 10 | * @param mustRunDelay 执行时间间隔 11 | * @return {Function} 12 | */ 13 | throttle: function (fn, delay, mustRunDelay) { 14 | let timer = null 15 | let t_start 16 | return function () { 17 | let context = this, args = arguments, t_curr = +new Date() 18 | clearTimeout(timer) 19 | if (!t_start) { 20 | t_start = t_curr 21 | } 22 | if (t_curr - t_start >= mustRunDelay) { 23 | fn.apply(context, args) 24 | t_start = t_curr 25 | } 26 | else { 27 | timer = setTimeout(function () { 28 | fn.apply(context, args) 29 | }, delay) 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/StringUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/22. 3 | * 存放公共方法 4 | */ 5 | module.exports = { 6 | /** 7 | * 函数节流 8 | * @param fn 函数 9 | * @param delay 多久执行一次 10 | * @param mustRunDelay 执行时间间隔 11 | * @return {Function} 12 | */ 13 | throttle: function (fn, delay, mustRunDelay) { 14 | let timer = null 15 | let t_start 16 | return function () { 17 | let context = this, args = arguments, t_curr = +new Date() 18 | clearTimeout(timer) 19 | if (!t_start) { 20 | t_start = t_curr 21 | } 22 | if (t_curr - t_start >= mustRunDelay) { 23 | fn.apply(context, args) 24 | t_start = t_curr 25 | } 26 | else { 27 | timer = setTimeout(function () { 28 | fn.apply(context, args) 29 | }, delay) 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /webpack4-basic-config/vendors-manifest.json: -------------------------------------------------------------------------------- 1 | {"name":"vendors_e100c0e8","content":{"./node_modules/webpack/buildin/global.js":{"id":0,"buildMeta":{"providedExports":true}},"./node_modules/vue/dist/vue.runtime.esm.js":{"id":2,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}},"./node_modules/timers-browserify/main.js":{"id":3,"buildMeta":{"providedExports":true}},"./node_modules/setimmediate/setImmediate.js":{"id":4,"buildMeta":{"providedExports":true}},"./node_modules/process/browser.js":{"id":5,"buildMeta":{"providedExports":true}},"./node_modules/vuex/dist/vuex.esm.js":{"id":6,"buildMeta":{"exportsType":"namespace","providedExports":["Store","install","mapState","mapMutations","mapGetters","mapActions","createNamespacedHelpers","default"]}},"./node_modules/vue-router/dist/vue-router.esm.js":{"id":7,"buildMeta":{"exportsType":"namespace","providedExports":["default"]}}}} -------------------------------------------------------------------------------- /webpack4-ssr-config/config/webpack.client.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack client配置 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const path = require('path') 8 | const baseConfig = require('./webpack.base.config')() 9 | const isProd = process.env.NODE_ENV === 'production' 10 | 11 | const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') 12 | const config = merge(baseConfig, { 13 | entry: { 14 | app: path.join(process.cwd(), 'client/entry-client.js'), 15 | }, 16 | mode: isProd ? 'production' : 'development', 17 | plugins: [ 18 | new webpack.DefinePlugin({ 19 | 'process.env.NODE_ENV': JSON.stringify(isProd ? 'production' : 'development'), 20 | 'process.env.VUE_ENV': '"client"' 21 | }), 22 | new VueSSRClientPlugin() 23 | ] 24 | }) 25 | 26 | module.exports = config 27 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/responsiveDesign.js: -------------------------------------------------------------------------------- 1 | /** 2 | * rem响应式方案的实现 3 | * 启用px到rem的转换enablePx2Rem配置项才会执行 4 | */ 5 | import { throttle } from './StringUtils' 6 | const enablePx2Rem = require('./../../app.config').webpack.enablePx2Rem 7 | if (enablePx2Rem) { 8 | const win = global 9 | const doc = win.document 10 | const baseWidth = 750 11 | const documentHTML = doc.documentElement 12 | let pixelRatio = 2 13 | 14 | /** 15 | * 设置html根字体 16 | */ 17 | function setRootFont () { 18 | const docWidth = documentHTML.getBoundingClientRect().width 19 | const scale = docWidth / baseWidth 20 | documentHTML.style.fontSize = `${scale * 100}px` 21 | pixelRatio = global.devicePixelRatio === 3 ? 3 : 2 22 | documentHTML.setAttribute('data-dpr', pixelRatio) 23 | } 24 | 25 | setRootFont() 26 | win.addEventListener('resize', throttle(setRootFont, 90, 100), false) 27 | } 28 | 29 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/responsiveDesign.js: -------------------------------------------------------------------------------- 1 | /** 2 | * rem响应式方案的实现 3 | * 启用px到rem的转换enablePx2Rem配置项才会执行 4 | */ 5 | import { throttle } from './StringUtils' 6 | const enablePx2Rem = require('./../../app.config').webpack.enablePx2Rem 7 | if (enablePx2Rem) { 8 | const win = global 9 | const doc = win.document 10 | const baseWidth = 750 11 | const documentHTML = doc.documentElement 12 | let pixelRatio = 2 13 | 14 | /** 15 | * 设置html根字体 16 | */ 17 | function setRootFont () { 18 | const docWidth = documentHTML.getBoundingClientRect().width 19 | const scale = docWidth / baseWidth 20 | documentHTML.style.fontSize = `${scale * 100}px` 21 | pixelRatio = global.devicePixelRatio === 3 ? 3 : 2 22 | documentHTML.setAttribute('data-dpr', pixelRatio) 23 | } 24 | 25 | setRootFont() 26 | win.addEventListener('resize', throttle(setRootFont, 90, 100), false) 27 | } 28 | 29 | -------------------------------------------------------------------------------- /react-base-webpack/config/http/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/6. 3 | * http 4 | * addRequestInterceptor 5 | * addResponseInterceptor 6 | */ 7 | import axios from 'axios' 8 | 9 | const defaultHeaders = { 10 | Accept: 'application/json, text/plain, */*; charset=utf-8', 11 | 'Content-Type': 'application/json; charset=utf-8', 12 | Pragma: 'no-cache', 13 | 'Cache-Control': 'no-cache', 14 | } 15 | // 设置默认头 16 | Object.assign(axios.defaults.headers.common, defaultHeaders) 17 | 18 | const methods = ['get', 'post', 'put', 'delete'] 19 | 20 | const http = {} 21 | methods.forEach(method => { 22 | http[method] = axios[method].bind(axios) 23 | }) 24 | 25 | export default http 26 | 27 | export const addRequestInterceptor = 28 | axios.interceptors.request.use.bind(axios.interceptors.request) 29 | 30 | export const addResponseInterceptor = 31 | axios.interceptors.response.use.bind(axios.interceptors.response) 32 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/http/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/6. 3 | * http 4 | * addRequestInterceptor 5 | * addResponseInterceptor 6 | */ 7 | import axios from 'axios' 8 | 9 | const defaultHeaders = { 10 | Accept: 'application/json, text/plain, */*; charset=utf-8', 11 | 'Content-Type': 'application/json; charset=utf-8', 12 | Pragma: 'no-cache', 13 | 'Cache-Control': 'no-cache', 14 | } 15 | // 设置默认头 16 | Object.assign(axios.defaults.headers.common, defaultHeaders) 17 | 18 | const methods = ['get', 'post', 'put', 'delete'] 19 | 20 | const http = {} 21 | methods.forEach(method => { 22 | http[method] = axios[method].bind(axios) 23 | }) 24 | 25 | export default http 26 | 27 | export const addRequestInterceptor = 28 | axios.interceptors.request.use.bind(axios.interceptors.request) 29 | 30 | export const addResponseInterceptor = 31 | axios.interceptors.response.use.bind(axios.interceptors.response) 32 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/http/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/6. 3 | * http 4 | * addRequestInterceptor 5 | * addResponseInterceptor 6 | */ 7 | import axios from 'axios' 8 | 9 | const defaultHeaders = { 10 | Accept: 'application/json, text/plain, */*; charset=utf-8', 11 | 'Content-Type': 'application/json; charset=utf-8', 12 | Pragma: 'no-cache', 13 | 'Cache-Control': 'no-cache', 14 | } 15 | // 设置默认头 16 | Object.assign(axios.defaults.headers.common, defaultHeaders) 17 | 18 | const methods = ['get', 'post', 'put', 'delete'] 19 | 20 | const http = {} 21 | methods.forEach(method => { 22 | http[method] = axios[method].bind(axios) 23 | }) 24 | 25 | export default http 26 | 27 | export const addRequestInterceptor = 28 | axios.interceptors.request.use.bind(axios.interceptors.request) 29 | 30 | export const addResponseInterceptor = 31 | axios.interceptors.response.use.bind(axios.interceptors.response) 32 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/store/modules/test.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | count: 0 3 | } 4 | 5 | const getters = { 6 | getCount: state => state.count 7 | } 8 | 9 | const mutations = { 10 | INCREMENT: (state) => { 11 | state.count++ 12 | }, 13 | DECREMENT: (state) => { 14 | state.count-- 15 | }, 16 | INITCOUNT: (state, COUNT) => { 17 | state.count = COUNT 18 | } 19 | } 20 | 21 | const actions = { 22 | increment({state, commit}) { 23 | commit('INCREMENT') 24 | }, 25 | decrement({state, commit}) { 26 | commit('DECREMENT') 27 | }, 28 | loading({commit}) { 29 | return new Promise(resolve => { 30 | setTimeout(() => { 31 | resolve() 32 | }, 1000) 33 | }).then(() => { 34 | commit('INITCOUNT', 67) 35 | }) 36 | }, 37 | resetCount({commit}) { 38 | commit('INITCOUNT', 67) 39 | } 40 | } 41 | 42 | export default { 43 | state, 44 | getters, 45 | mutations, 46 | actions 47 | } 48 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/views/business/bus-detial.vue: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /webpack/test/compiler.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | import path from 'path' 3 | import webpack from 'webpack' 4 | import memoryfs from 'memory-fs' 5 | 6 | function resolve(dir) { 7 | return path.resolve(process.cwd(), dir) 8 | } 9 | 10 | export default (fixture, options = {}) => { 11 | const compiler = webpack({ 12 | context: __dirname, 13 | entry: `./${fixture}`, 14 | output: { 15 | path: path.resolve(__dirname), 16 | filename: 'bundle.js', 17 | }, 18 | module: { 19 | rules: [{ 20 | test: /\.txt$/, 21 | use: { 22 | loader: resolve('loaders/ml-loader.js'), 23 | options: { 24 | name: 'Alice' 25 | } 26 | } 27 | }] 28 | } 29 | }) 30 | compiler.outputFileSystem = new memoryfs() 31 | return new Promise((resolve, reject) => { 32 | compiler.run((err, stats) => { 33 | if (err) reject(err) 34 | resolve(stats) 35 | }) 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /koa-app/README.md: -------------------------------------------------------------------------------- 1 | # Koa服务 2 | 3 | ## Package 说明 4 | * koa # 主程 5 | * koa-router # 路由 6 | * koa-compress # 压缩响应 7 | * koa-logger # 日志 8 | * koa-session # session 9 | * koa-static # 静态资源服务 10 | * keygrip # 加密 11 | * @babel/core # 支持es6语法 12 | * @babel/preset-env # 支持es6语法 13 | * @babel/register # 支持es6语法 14 | * axios # http请求 15 | * mongoose # Mongoose是设计用于异步环境的MongoDB对象建模工具 16 | * nodemon # nodemon是一种工具,可在检测到目录中的文件更改时通过自动重新启动节点应用程序来帮助开发基于node.js的应用程序 17 | 18 | ## 目录 19 | ``` bash 20 | ├── app # Node代码目录 21 | │   ├── db # mangodb数据库操作 22 | │   │   ├── # 23 | │   │   └── # 24 | │   ├── middleWares # koa中间件 25 | │   ├── middle # koa2中间件目录 26 | │   └── router # koa路由封装 27 | ├── log # pm2日志输出目录 28 | ├── node_modules # node包 29 | ├── .gitignore # git配置 30 | ├── app.config.js # app配置文件 31 | ├── package.json # 32 | ├── package-lock.json # 33 | ├── pm2.config.js # 项目pm2配置 34 | ├── pm2.md # pm2的api文档 35 | ├── postcss.config.js # postcss配置文件 36 | └── README.md # 文档 37 | ``` 38 | -------------------------------------------------------------------------------- /react-base-webpack/index.template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /webpack3-basic-config/index.template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <%= htmlWebpackPlugin.options.gaScripts %> 18 | 19 | 20 |
21 | 22 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack client配置 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const base = require('./webpack.config.base')() 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const config = merge(base, { 10 | devtool: '#cheap-module-source-map', 11 | mode: 'development', 12 | plugins: [ 13 | new webpack.DefinePlugin({ 14 | 'process.env': { 15 | NODE_ENV: JSON.stringify("development"), 16 | }, 17 | }), 18 | // 全局开启代码热替换 19 | new webpack.NamedModulesPlugin(), 20 | new webpack.HotModuleReplacementPlugin(), 21 | new FriendlyErrorsPlugin(), 22 | ] 23 | }) 24 | Object.keys(config.entry).forEach(function (name) { 25 | config.entry[name] = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true'].concat(config.entry[name]) 26 | }) 27 | 28 | module.exports = config 29 | -------------------------------------------------------------------------------- /webpack4-ssr-config/index.template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/router.js: -------------------------------------------------------------------------------- 1 | /* loading */ 2 | import VueRouter from 'vue-router' 3 | import routes from './routes' 4 | 5 | const ProgressBar = require('progressbar.js') 6 | 7 | const router = new VueRouter({ 8 | mode: 'history', 9 | routes 10 | }) 11 | 12 | const doc = global.document 13 | 14 | // 响应式 SVG 进度条 15 | let line = null 16 | 17 | router.beforeEach((to, from, next) => { 18 | // 进度条开始 19 | if (line) { line.destroy() } 20 | line = new ProgressBar.Line('body', { 21 | color: '#009ce5', 22 | strokeWidth: 0.2, 23 | svgStyle: {position: 'fixed', zIndex: '10001', top: 0, left: 0, right: 0, maxHeight: '2px'} 24 | }) 25 | line.animate(0.8, {duration: 500}) 26 | next() 27 | }) 28 | 29 | router.afterEach((route) => { 30 | // 设置标题 31 | doc.title = route.meta.title || '首页' 32 | // 进度条结束 33 | if (line) { 34 | line.animate(1, {duration: 1000}, () => { 35 | line.destroy() 36 | line = null 37 | }) 38 | } 39 | }) 40 | 41 | export default router 42 | -------------------------------------------------------------------------------- /koa-app/app/middleWares/limitFlow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file limitFlow Node服务限制流量处理中间件 3 | * @desc 业务代码中的逻辑限流 4 | * @desc 常见的限流算法有:计数器、令牌桶、漏桶。这些都属于单机限流的范畴 5 | * @desc 另外为了限制某个资源被每个用户或者商户的访问次数,5s只能访问2次,或者一天只能调用1000次。这种需求,单机限流是无法实现的,这时就需要通过集群限流进行实现。 6 | * 如何实现?为了控制访问次数,肯定需要一个计数器,而且这个计数器只能保存在第三方服务,比如redis。 7 | */ 8 | import appConfig from './../../app.config' 9 | 10 | const { enable, upperLimit, rate } = appConfig.currentLimitedConfig 11 | 12 | export default () => { 13 | let bucket = 0 14 | const callback = () => { 15 | setTimeout(() => { 16 | if (bucket < upperLimit) { 17 | bucket += 1 18 | } 19 | callback() 20 | }, 1000 / rate) 21 | } 22 | callback() 23 | return async (ctx, next) => { 24 | // console.log('当前Token bucket ', bucket) 25 | if (enable && bucket <= 0) { 26 | console.log('Token bucket 耗尽,开启限流') 27 | return ctx.body = { data: null, status: false, message: '亲~人太多,被挤爆了!' } 28 | } 29 | bucket -= 1; 30 | await next() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/config.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | // 引入http请求插件 4 | import http from '@config/utils/http' 5 | // 引入log日志插件 6 | import vueLogger from '@config/utils/logger/vue-logger' 7 | import { addRequestInterceptor, addResponseInterceptor } from '@config/utils/http/http' 8 | 9 | // 注册插件 10 | Vue.use(http) 11 | Vue.use(vueLogger) 12 | Vue.use(VueRouter) 13 | 14 | // request前自动添加api配置 15 | addRequestInterceptor( 16 | (config) => { 17 | // config.url = `/api${config.url}` 18 | return config 19 | }, 20 | (error) => { 21 | return Promise.reject(error) 22 | } 23 | ) 24 | 25 | // 返回response前处理 26 | addResponseInterceptor( 27 | (response) => { 28 | // 在这里统一前置处理请求响应 29 | if (Number(response.status) !== 200) { 30 | // 全局notify有问题,还是自己处理吧 31 | return Promise.reject(response.data) 32 | } 33 | return Promise.resolve(response.data) 34 | }, 35 | (error) => { 36 | return Promise.reject(error || '出错了') 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /koa-app/app/app.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa' 2 | import Logger from 'koa-logger' 3 | import Compress from 'koa-compress' 4 | import Session from 'koa-session' 5 | import KeyGrip from 'keygrip' 6 | import appConfig from './../app.config' 7 | import middles from './middleWares' 8 | import router from './router' 9 | 10 | const app = new Koa() 11 | /** 设置签名cookie密钥。*/ 12 | app.keys = new KeyGrip(['zdliuccit', 'ml', 'app'], 'sha256'); 13 | 14 | /** session设置 */ 15 | const SESSION_CONFIG = { 16 | key: 'ml-app', /** cookie键 */ 17 | maxAge: 60 * 60 * 24 * 1000, /** session过期时间 */ 18 | renew: false, /** 当会话即将过期时续订会话,因此我们可以始终保持用户登录。*/ 19 | }; 20 | app.use(Session(SESSION_CONFIG, app)); 21 | app.use(Logger()) 22 | app.use(Compress()) 23 | 24 | /** 25 | * 启动自定义中间件 26 | */ 27 | middles(app) 28 | 29 | /** 30 | * 启动路由 31 | */ 32 | router(app) 33 | 34 | /** 35 | * app错误监听 36 | */ 37 | app.on('error', (err) => { 38 | console.error('Server error: \n%s\n%s ', err.stack || '') 39 | }) 40 | 41 | app.listen(appConfig.appPort) 42 | -------------------------------------------------------------------------------- /react-base-webpack/client/view/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Layout } from 'antd' 3 | 4 | const { Sider, Header, Content, Footer } = Layout 5 | 6 | class Index extends React.Component { 7 | state = { 8 | collapsed: false 9 | } 10 | toggle = () => { 11 | this.setState({ 12 | collapsed: !this.state.collapsed 13 | }) 14 | } 15 | 16 | render() { 17 | // 设置Sider的minHeight可以使左右自适应对齐 18 | return ( 19 |
20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 | React-Admin ©2018 Created by 137596665@qq.com
30 |
31 |
32 |
33 | ) 34 | } 35 | } 36 | 37 | export default Index -------------------------------------------------------------------------------- /webpack4-basic-config/src/index.js: -------------------------------------------------------------------------------- 1 | import '@babel/polyfill' 2 | import Vue from 'vue' 3 | import './config' 4 | import router from './router' 5 | import App from './app.vue' 6 | import vueStorage from './utils/storage' 7 | 8 | /** 9 | * @param {Object} Vue Vue 10 | * @param {router} [router=undefined] VueRouter 实例化对象 11 | * @param [] 路由白名单 12 | * @param (storage) => {} 回调函数 13 | */ 14 | const store = vueStorage(Vue, router, [], (storage, to, from) => { 15 | return new Promise((resolve) => { 16 | // const { whether } = storage.getItem('userObject', false) || JSON.parse(localStorage.getItem('userObject')) || {} 17 | // if (!whether && to.path !== '/login') { 18 | // global.location.href = '/login' 19 | // } else { 20 | // storage.setItem('userObject', JSON.parse(localStorage.getItem('userObject')), false) 21 | resolve(storage, to, from) 22 | // } 23 | }) 24 | }) 25 | 26 | /*eslint-disable*/ 27 | new Vue({ 28 | el: '#app', 29 | router, 30 | store, 31 | render: h => h(App) 32 | }) 33 | -------------------------------------------------------------------------------- /webpack4-basic-config/index.template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /webpack/loaders/ml-loader.js: -------------------------------------------------------------------------------- 1 | const loaderUtils = require('loader-utils') 2 | const validateOptions = require('schema-utils') 3 | const fs = require('fs') 4 | const path = require('path') 5 | const schema = { 6 | type: 'object', 7 | properties: { 8 | test: { 9 | type: 'string' 10 | } 11 | } 12 | } 13 | module.exports = function (source) { 14 | const options = loaderUtils.getOptions(this) 15 | const callback = this.async() 16 | const msPath = path.resolve('loaders/ms.js') 17 | 18 | this.addDependency(msPath) 19 | console.log('options', options) 20 | validateOptions(schema, options, 'Example Loader') 21 | 22 | fs.readFile(msPath, 'utf-8', function (err, header) { 23 | if (err) return callback(err) 24 | callback(null, header + "\n" + source); 25 | }) 26 | // return source 27 | } 28 | 29 | module.exports = function (source) { 30 | const options = loaderUtils.getOptions(this) 31 | source = source.replace(/\[name\]/g, options.name) 32 | return `export default ${JSON.stringify(source)}` 33 | } 34 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/views/business/routes.js: -------------------------------------------------------------------------------- 1 | import businessList from './business-list.vue' 2 | import businessDetail from './bus-detial.vue' 3 | import businessAddEdit from './bus-add-edit.vue' 4 | 5 | const routes = [ 6 | { 7 | path: '/', 8 | name: 'businessList', 9 | component: businessList, 10 | meta: { 11 | title: '商家列表', 12 | sidebarLink: '/business/list' 13 | }, 14 | }, 15 | { 16 | path: 'add', 17 | name: 'businessAdd', 18 | component: businessAddEdit, 19 | meta: { 20 | title: '添加商家', 21 | sidebarLink: '/business/list' 22 | }, 23 | }, 24 | { 25 | path: 'edit/:id', 26 | name: 'businessEdit', 27 | component: businessAddEdit, 28 | meta: { 29 | title: '修改商家', 30 | sidebarLink: '/business/list' 31 | }, 32 | }, 33 | { 34 | path: 'detail/:id', 35 | name: 'businessDetail', 36 | component: businessDetail, 37 | meta: { 38 | title: '商家详情', 39 | sidebarLink: '/business/list' 40 | }, 41 | }, 42 | ] 43 | 44 | export default routes 45 | -------------------------------------------------------------------------------- /react-base-webpack/client/utils/Session.js: -------------------------------------------------------------------------------- 1 | const LOGIN_COOKIE_NAME = 'sessionId' 2 | 3 | export function isAuthenticated() { 4 | return _getCookie(LOGIN_COOKIE_NAME) 5 | } 6 | 7 | export function authenticateSuccess(token) { 8 | _setCookie(LOGIN_COOKIE_NAME, token) 9 | } 10 | 11 | export function logout() { 12 | _setCookie(LOGIN_COOKIE_NAME, '', 0) 13 | } 14 | 15 | function _getCookie(name) { 16 | let start, end 17 | if (document.cookie.length > 0) { 18 | start = document.cookie.indexOf(name + '=') 19 | if (start !== -1) { 20 | start = start + name.length + 1 21 | end = document.cookie.indexOf(';', start) 22 | if (end === -1) { 23 | end = document.cookie.length 24 | } 25 | return unescape(document.cookie.substring(start, end)) 26 | } 27 | } 28 | return '' 29 | } 30 | 31 | function _setCookie(name, value, expire) { 32 | let date = new Date() 33 | date.setDate(date.getDate() + expire) 34 | document.cookie = name + '=' + escape(value) + '; path=/' + 35 | (expire ? ';expires=' + date.toGMTString() : '') 36 | } -------------------------------------------------------------------------------- /webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loader", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "loaders/ml-loader.js", 6 | "scripts": { 7 | "test": "jest", 8 | "start": "webpack --profile --config webpack.config.js --hide-modules " 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "autoprefixer": "9.4.2", 14 | "babel-core": "^6.26.3", 15 | "babel-jest": "^24.9.0", 16 | "babel-polyfill": "^6.26.0", 17 | "babel-preset-env": "^1.7.0", 18 | "css-loader": "^3.4.0", 19 | "extract-css-chunks-webpack-plugin": "3.2.1", 20 | "jest": "^24.9.0", 21 | "loader-utils": "^1.2.3", 22 | "memory-fs": "^0.5.0", 23 | "postcss": "7.0.6", 24 | "postcss-loader": "3.0.0", 25 | "postcss-pxtorem": "4.0.1", 26 | "progressbar.js": "^1.0.1", 27 | "regenerator-runtime": "^0.13.3", 28 | "schema-utils": "^2.6.1", 29 | "stylus": "0.54.5", 30 | "stylus-loader": "3.0.2", 31 | "vue-style-loader": "4.1.2", 32 | "webpack": "^4.41.5", 33 | "webpack-cli": "^3.3.10" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/views/test/data.vue: -------------------------------------------------------------------------------- 1 | 11 | 35 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/views/test/ajax.vue: -------------------------------------------------------------------------------- 1 | 9 | 34 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/config.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | // 引入http请求插件 3 | import http from './../config/http' 4 | // 引入log日志插件 5 | import { addRequestInterceptor, addResponseInterceptor } from './../config/http/http' 6 | import titleMixin from './utils/title' 7 | // 引入log日志插件 8 | import vueLogger from './../config/logger/vue-logger' 9 | 10 | // 注册插件 11 | Vue.use(http) 12 | Vue.use(vueLogger) 13 | Vue.mixin(titleMixin) 14 | 15 | // request前自动添加api配置 16 | addRequestInterceptor( 17 | (config) => { 18 | /*统一加/api前缀*/ 19 | config.url = `/api${config.url}` 20 | return config 21 | }, 22 | (error) => { 23 | return Promise.reject(error) 24 | } 25 | ) 26 | 27 | // http 返回response前处理 28 | addResponseInterceptor( 29 | (response) => { 30 | /*todo 在这里统一前置处理请求响应 */ 31 | return Promise.resolve(response.data) 32 | }, 33 | (error) => { 34 | /* 35 | * todo 统一处理500、400等错误状态 36 | * 这里reject下,交给entry-server.js的处理 37 | */ 38 | const { response, request } = error 39 | return Promise.reject({ code: response.status, data: response.data, method: request.method, path: request.path }) 40 | } 41 | ) -------------------------------------------------------------------------------- /webpack3-basic-config/client/router.js: -------------------------------------------------------------------------------- 1 | /* loading */ 2 | import VueRouter from 'vue-router' 3 | import routes from './routes' 4 | const ProgressBar = require('progressbar.js') 5 | 6 | const router = new VueRouter({ 7 | mode: 'history', 8 | // base: '/book', 9 | routes 10 | }) 11 | 12 | const doc = global.document 13 | 14 | // 响应式 SVG 进度条 15 | let line = null 16 | 17 | router.beforeEach((to, from, next) => { 18 | // 进度条开始 19 | if (line) line.destroy() 20 | line = new ProgressBar.Line('body', { 21 | color: '#009ce5', 22 | strokeWidth: 0.2, 23 | svgStyle: { 24 | position: 'fixed', 25 | zIndex: '10001', 26 | top: 0, 27 | left: 0, 28 | right: 0, 29 | maxHeight: '2px' 30 | } 31 | }) 32 | line.animate(0.8, { 33 | duration: 500 34 | }) 35 | next() 36 | }) 37 | 38 | router.afterEach((route) => { 39 | // 设置标题 40 | doc.title = route.meta.title || '首页' 41 | // 进度条结束 42 | if (line) { 43 | line.animate(1, { 44 | duration: 1000 45 | }, () => { 46 | line.destroy() 47 | line = null 48 | }) 49 | } 50 | }) 51 | 52 | export default router 53 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/assets/css/reset.css: -------------------------------------------------------------------------------- 1 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body, button, input, select, textarea { 7 | font: 12PX/1.5 tahoma, arial, 'microsoft yahei', sans-serif 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6 { 11 | font-size: 100%; 12 | } 13 | 14 | address, cite, dfn, em, var { 15 | font-style: normal; 16 | } 17 | 18 | code, kbd, pre, samp { 19 | font-family: couriernew, courier, monospace; 20 | } 21 | 22 | small { 23 | font-size: 12PX; 24 | } 25 | 26 | ul, ol { 27 | list-style: none; 28 | } 29 | 30 | a { 31 | text-decoration: none; 32 | } 33 | 34 | a:hover { 35 | text-decoration: underline; 36 | } 37 | 38 | sup { 39 | vertical-align: text-top; 40 | } 41 | 42 | sub { 43 | vertical-align: text-bottom; 44 | } 45 | 46 | legend { 47 | color: #000; 48 | } 49 | 50 | fieldset, img { 51 | border: 0; 52 | } 53 | 54 | button, input, select, textarea { 55 | font-size: 100%; 56 | } 57 | 58 | table { 59 | border-collapse: collapse; 60 | border-spacing: 0; 61 | } -------------------------------------------------------------------------------- /webpack3-basic-config/client/assets/css/common.css: -------------------------------------------------------------------------------- 1 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body, button, input, select, textarea { 7 | font: 12PX/1.5 tahoma, arial, 'microsoft yahei', sans-serif 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6 { 11 | font-size: 100%; 12 | } 13 | 14 | address, cite, dfn, em, var { 15 | font-style: normal; 16 | } 17 | 18 | code, kbd, pre, samp { 19 | font-family: couriernew, courier, monospace; 20 | } 21 | 22 | small { 23 | font-size: 12PX; 24 | } 25 | 26 | ul, ol { 27 | list-style: none; 28 | } 29 | 30 | a { 31 | text-decoration: none; 32 | } 33 | 34 | a:hover { 35 | text-decoration: underline; 36 | } 37 | 38 | sup { 39 | vertical-align: text-top; 40 | } 41 | 42 | sub { 43 | vertical-align: text-bottom; 44 | } 45 | 46 | legend { 47 | color: #000; 48 | } 49 | 50 | fieldset, img { 51 | border: 0; 52 | } 53 | 54 | button, input, select, textarea { 55 | font-size: 100%; 56 | } 57 | 58 | table { 59 | border-collapse: collapse; 60 | border-spacing: 0; 61 | } -------------------------------------------------------------------------------- /webpack3-basic-config/config/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | const postcss = require('./postcss.conf')() 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 3 | 4 | /** 5 | * 组装vue-loader配置 6 | * @param {string} env 环境,可能的值prod|dev 7 | * @return {object} 配置 8 | **/ 9 | module.exports = function (env) { 10 | const config = { 11 | loader: 'vue-loader', 12 | options: { 13 | // 去除模板中的空格 14 | preserveWhitespace: false, 15 | // postcss配置,把vue文件中的样式部分,做后续处理 16 | postcss, 17 | }, 18 | } 19 | // webpack打包时,提取css 20 | if (env === 'prod') { 21 | // 生产环境 22 | config.options.loaders = { 23 | css: ExtractTextPlugin.extract({ 24 | use: ['css-loader'], 25 | fallback: 'vue-style-loader', 26 | }), 27 | stylus: ExtractTextPlugin.extract({ 28 | use: ['css-loader', 'stylus-loader'], 29 | fallback: 'vue-style-loader', 30 | }), 31 | } 32 | } else { 33 | // 开发环境 34 | config.options.loaders = { 35 | css: ['vue-style-loader', 'css-loader'], 36 | stylus: ['vue-style-loader', 'css-loader', 'stylus-loader',], 37 | } 38 | } 39 | return config 40 | } 41 | -------------------------------------------------------------------------------- /react-base-webpack/config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack dev配置 3 | * Created by zdliuccit on 2018/11/1. 4 | */ 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const base = require('./webpack.config.base')() 8 | const appWebpack = require('./../app.config').webpack 9 | 10 | Object.keys(appWebpack.entry).forEach(function (name) { 11 | appWebpack.entry[name] = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true'].concat(appWebpack.entry[name]) 12 | }) 13 | const config = merge(base, { 14 | mode: 'development', 15 | devtool: '#cheap-module-source-map', 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.css$/, 20 | use: ['style-loader', 'css-loader', 'postcss-loader'] 21 | }, 22 | { 23 | test: /\.scss$/, 24 | use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] 25 | }, 26 | ] 27 | }, 28 | plugins: [ 29 | new webpack.DefinePlugin({ 30 | 'process.env': { 31 | NODE_ENV: '"development"', 32 | REACT_ENV: '"client"', 33 | }, 34 | }), 35 | new webpack.HotModuleReplacementPlugin(), 36 | ] 37 | }, appWebpack) 38 | 39 | module.exports = config 40 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/config.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import http from '@config/utils/http' 4 | import vueLogger from '@config/utils/logger/vue-logger' 5 | import {addRequestInterceptor, addResponseInterceptor} from '@config/utils/http/http' 6 | import elementUI from 'element-ui' 7 | import 'element-ui/lib/theme-chalk/index.css' 8 | 9 | // 引入自定义业务组件 10 | import components from './components' 11 | // 注册插件 12 | Vue.use(http) 13 | Vue.use(vueLogger) 14 | Vue.use(VueRouter) 15 | Vue.use(elementUI) 16 | 17 | components.forEach(comp => { 18 | Vue.component(`ml-${comp.name}`, comp) 19 | }) 20 | 21 | // request前自动添加api配置 22 | addRequestInterceptor( 23 | (config) => { 24 | config.url = `/api${config.url}` 25 | return config 26 | }, 27 | (error) => { 28 | return Promise.reject(error) 29 | } 30 | ) 31 | 32 | // 返回response前处理 33 | addResponseInterceptor( 34 | (response) => { 35 | // 在这里统一前置处理请求响应 36 | if (Number(response.status) !== 200) { 37 | // 全局notify有问题,还是自己处理吧 38 | return Promise.reject(response.data) 39 | } 40 | return Promise.resolve(response.data) 41 | }, 42 | (error) => { 43 | return Promise.reject(error || '出错了') 44 | } 45 | ) 46 | -------------------------------------------------------------------------------- /koa-app/app/model/UserModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * User model 3 | */ 4 | 5 | import mongoose, { Schema } from 'mongoose' 6 | 7 | const UserSchema = Schema({ 8 | account: { 9 | type: String, 10 | required: true, 11 | trim: true 12 | }, 13 | password: { 14 | type: String, 15 | required: true, 16 | trim: true 17 | }, 18 | nickName: { 19 | type: String, 20 | required: true, 21 | trim: true 22 | }, 23 | phone: { 24 | type: Number, 25 | min: 10, 26 | max: 20, 27 | required: true, 28 | }, 29 | createTime: { 30 | type: Date, 31 | default: Date.now 32 | } 33 | }); 34 | 35 | UserSchema.statics = { 36 | /** 37 | * 查找 38 | * @param data 39 | */ 40 | async findUser(data = {}) { 41 | return await this.findOne(data); 42 | }, 43 | /** 44 | * 创建用户 45 | * @param data 46 | */ 47 | async register(data = {}) { 48 | const result = await this.create(data); 49 | return result 50 | }, 51 | /** 52 | * 删除 53 | * @param data 54 | */ 55 | async delete(data) { 56 | const result = await this.remove(data); 57 | return result 58 | }, 59 | } 60 | 61 | const UserModel = mongoose.model('User', UserSchema); 62 | 63 | export default UserModel 64 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/koa.server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * koa2 server 入口 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const Koa = require('koa') 6 | const koaCompress = require('koa-compress')() 7 | 8 | const loggerMiddleware = require('koa-logger')() 9 | const staticMiddleWare = require('./middle/staticMiddleWare') 10 | const errorMiddleware = require('./middle/errorMiddleWare') 11 | const proxyMiddleWare = require('./middle/proxyMiddleWare') 12 | const vueKoaSSR = require('./vue.koa.ssr') 13 | const currentIP = require('ip').address() 14 | 15 | const appConfig = require('./../app.config') 16 | const uri = `http://${currentIP}:${appConfig.appPort}` 17 | 18 | // koa server 19 | const app = new Koa() 20 | 21 | // 中间件, 22 | const middleWares = [ 23 | // 打印请求与响应 日志 24 | loggerMiddleware, 25 | // 压缩响应 26 | koaCompress, 27 | // 错误处理 28 | errorMiddleware, 29 | // 静态资源中间件 30 | staticMiddleWare(), 31 | ] 32 | middleWares.forEach((middleware) => { 33 | if (!middleware) { 34 | return 35 | } 36 | app.use(middleware) 37 | }) 38 | 39 | // vue ssr处理 40 | vueKoaSSR(app, uri) 41 | 42 | // http代理中间件 43 | app.use(proxyMiddleWare()) 44 | 45 | console.log(`\n> Starting server... ${uri} \n`) 46 | 47 | // 错误处理 48 | app.on('error', (err) => { 49 | // console.error('Server error: \n%s\n%s ', err.stack || '') 50 | }) 51 | 52 | app.listen(appConfig.appPort) 53 | -------------------------------------------------------------------------------- /webpack4-ssr-config/client/store/modules/test.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | count: 0, 3 | testResult: null 4 | } 5 | 6 | const getters = { 7 | getCount: state => state.count, 8 | getTestResult: state => state.testResult 9 | } 10 | 11 | const mutations = { 12 | INCREMENT: (state) => { 13 | state.count++ 14 | }, 15 | DECREMENT: (state) => { 16 | state.count-- 17 | }, 18 | INITCOUNT: (state, COUNT) => { 19 | state.count = COUNT 20 | }, 21 | TESTRESULT: (state, data) => { 22 | state.testResult = data 23 | } 24 | } 25 | 26 | const actions = { 27 | increment({ state, commit }) { 28 | commit('INCREMENT') 29 | }, 30 | decrement({ state, commit }) { 31 | commit('DECREMENT') 32 | }, 33 | loading({ commit, rootState: { $http } }) { 34 | // return new Promise(resolve => { 35 | // setTimeout(() => { 36 | // resolve() 37 | // }, 1000) 38 | // }).then(() => { 39 | // commit('INITCOUNT', 67) 40 | // commit('INITCOUNT', 67) 41 | // }) 42 | return $http.get('/v3/assistant/coordinate/convert?key=ff0bcf778c5eeb93bd8b068b6e3f7781&locations=116.481499,39.990475|116.481499,39.990375') 43 | .then(res => { 44 | commit('INITCOUNT', 269) 45 | commit('TESTRESULT', res) 46 | }) 47 | }, 48 | resetCount({ commit }) { 49 | commit('INITCOUNT', 67) 50 | } 51 | } 52 | 53 | export default { 54 | state, 55 | getters, 56 | mutations, 57 | actions 58 | } 59 | -------------------------------------------------------------------------------- /koa-app/app/plugins/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2019/1/14. 3 | * @file axios封装 4 | * export default http 接口请求 5 | * export addRequestInterceptor 请求前拦截器 6 | * export addResponseInterceptor 请求后拦截器 7 | * export setCookies 同步cookie 8 | */ 9 | import axios from 'axios' 10 | 11 | const currentIP = require('ip').address() 12 | const appConfig = require('./../../app.config') 13 | 14 | const defaultHeaders = { 15 | Accept: 'application/json, text/plain, */*; charset=utf-8', 16 | 'Content-Type': 'application/json; charset=utf-8', 17 | Pragma: 'no-cache', 18 | 'Cache-Control': 'no-cache', 19 | } 20 | Object.assign(axios.defaults.headers.common, defaultHeaders) 21 | 22 | if (!process.browser) { 23 | axios.defaults.baseURL = `http://${currentIP}:${appConfig.appPort}` 24 | } 25 | const methods = ['get', 'post', 'put', 'delete', 'patch', 'options', 'request', 'head'] 26 | 27 | const $http = {} 28 | methods.forEach(method => { 29 | $http[method] = axios[method].bind(axios) 30 | }) 31 | 32 | export const addRequestInterceptor = (resolve, reject) => { 33 | if (axios.interceptors.request.handlers.length === 0) axios.interceptors.request.use(resolve, reject) 34 | } 35 | export const addResponseInterceptor = (resolve, reject) => { 36 | if (axios.interceptors.response.handlers.length === 0) axios.interceptors.response.use(resolve, reject) 37 | } 38 | export const setCookies = Cookies => axios.defaults.headers.cookie = Cookies 39 | 40 | export default $http 41 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/webpack.server.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack server配置 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const webpack = require('webpack') 6 | const path = require('path') 7 | const merge = require('webpack-merge') 8 | const nodeExternals = require('webpack-node-externals') 9 | const baseConfig = require('./webpack.base.config')() 10 | const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') 11 | const isProd = process.env.NODE_ENV === 'production' 12 | 13 | module.exports = merge(baseConfig, { 14 | // 指定生成后的运行环境在node 15 | target: 'node', 16 | mode: isProd ? 'production' : 'development', 17 | // 配置编译的入口文件 18 | entry: path.join(process.cwd(), 'client/entry-server.js'), 19 | // 设置输出文件名,并设置模块导出为commonjs2类型 20 | output: { 21 | filename: 'server-bundle.js', 22 | libraryTarget: 'commonjs2' 23 | }, 24 | // 外置化应用程序依赖模块。可以使服务器构建速度更快, 25 | // 并生成较小的 bundle 文件。 26 | externals: nodeExternals({ 27 | // 不要外置化 webpack 需要处理的依赖模块。 28 | // 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件, 29 | // 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单 30 | whitelist: [/\.vue$/, /\.css$/] 31 | }), 32 | // 这是将服务器的整个输出 33 | // 构建为单个 JSON 文件的插件。 34 | // 默认文件名为 `vue-ssr-server-bundle.json` 35 | plugins: [ 36 | new webpack.DefinePlugin({ 37 | 'process.env.NODE_ENV': JSON.stringify(isProd ? 'production' : 'development'), 38 | 'process.env.VUE_ENV': '"server"' 39 | }), 40 | new VueSSRServerPlugin() 41 | ] 42 | }) 43 | -------------------------------------------------------------------------------- /webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const ExtractCssChunks = require("extract-css-chunks-webpack-plugin") 3 | 4 | const mlPlugin = require('./loaders/ms-plugin'); 5 | 6 | function resolve(dir) { 7 | return path.resolve(process.cwd(), dir) 8 | } 9 | 10 | module.exports = { 11 | mode: 'development', 12 | devtool: '#cheap-module-source-map', 13 | // 入口模块配置 14 | entry: resolve('src/index.js'), 15 | // 输出模块配置 16 | output: { 17 | // 输出到这个目录下 18 | path: resolve('dist'), 19 | // 生成的文件名, [name] 即为entry配置中的key 20 | filename: '[name].js', 21 | // 异步模块文件名 22 | chunkFilename: '[id].js', 23 | publicPath: '/' 24 | }, 25 | // 寻找模块时的一些缺省设置 26 | resolveLoader: { 27 | modules: ['node_modules', resolve('loaders')], 28 | }, 29 | resolve: { 30 | // 补充扩展名 31 | extensions: ['.js'], 32 | }, 33 | module: { 34 | rules: [ 35 | { 36 | test: /\.js$/, 37 | use: [{ 38 | loader: 'ml-loader', 39 | options: { 40 | name: 'ml', 41 | test: '123213', 42 | } 43 | }], 44 | }, 45 | { 46 | test: /\.css$/, 47 | use: [ExtractCssChunks.loader, 'css-loader'], 48 | }, 49 | ] 50 | }, 51 | plugins: [ 52 | new ExtractCssChunks({ 53 | filename: 'assets/css/[name].[chunkhash:8].css', 54 | chunkFilename: 'assets/css/[id].[chunkhash:8].css', 55 | }), 56 | new mlPlugin({ tip: '参数' }) 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/http/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2019/1/14. 3 | * @file axios封装 4 | * export default http 接口请求 5 | * export addRequestInterceptor 请求前拦截器 6 | * export addResponseInterceptor 请求后拦截器 7 | * export setCookies 同步cookie 8 | */ 9 | import axios from 'axios' 10 | 11 | const currentIP = require('ip').address() 12 | const appConfig = require('./../../app.config') 13 | 14 | const defaultHeaders = { 15 | Accept: 'application/json, text/plain, */*; charset=utf-8', 16 | 'Content-Type': 'application/json; charset=utf-8', 17 | Pragma: 'no-cache', 18 | 'Cache-Control': 'no-cache', 19 | } 20 | Object.assign(axios.defaults.headers.common, defaultHeaders) 21 | 22 | if (!process.browser) { 23 | axios.defaults.baseURL = `http://${currentIP}:${appConfig.appPort}` 24 | } 25 | const methods = ['get', 'post', 'put', 'delete', 'patch', 'options', 'request', 'head'] 26 | 27 | const http = {} 28 | methods.forEach(method => { 29 | http[method] = axios[method].bind(axios) 30 | }) 31 | 32 | export const addRequestInterceptor = (resolve, reject) => { 33 | if (axios.interceptors.request.handlers.length === 0) axios.interceptors.request.use(resolve, reject) 34 | } 35 | export const addResponseInterceptor = (resolve, reject) => { 36 | if (axios.interceptors.response.handlers.length === 0) axios.interceptors.response.use(resolve, reject) 37 | } 38 | export const setCookies = Cookies => axios.defaults.headers.cookie = Cookies 39 | 40 | export default http 41 | -------------------------------------------------------------------------------- /react-base-webpack/config/middle/proxyToken.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2018/11/1. 3 | * proxyMiddleWare中间件token处理 4 | * @type {string} 5 | */ 6 | const logger = require('../logger/koa-logger')('proxyToken') 7 | // 带token http头 8 | const accessTokenHeaderName = 'x-access-token' 9 | // 请求来源 http头 10 | const accessOriginHeaderName = 'x-access-origin' 11 | 12 | // 默认cookie配置 13 | const defaultCookieConfig = { 14 | name: '_atk', 15 | httpOnly: true, 16 | overwrite: true, 17 | // 长期有效(20年) 18 | maxAge: 1000 * 60 * 60 * 24 * 365 * 20, 19 | } 20 | 21 | module.exports = function createRedis() { 22 | const cookieConfig = Object.assign({}, defaultCookieConfig) 23 | return { 24 | // 处理请求时的token操作 25 | async handleRequest(ctx) { 26 | return { 27 | [accessOriginHeaderName]: ctx.query.accessOrigin || 'WAP', 28 | } 29 | }, 30 | 31 | // 处理响应时的token操作 32 | async handleResponse(ctx) { 33 | logger.info('HandleResponse headers:', ctx.response.headers) 34 | const responseToken = ctx.response.headers[accessTokenHeaderName] 35 | 36 | // 如果后端响应头里没有token,则不设置cookie 37 | if (!responseToken) return 38 | logger.info(`Token found: ${responseToken}', it will be set to cookie.`) 39 | 40 | // 这里koa-better-http-proxy已经把代理响应头复制到原始响应头了 41 | ctx.cookies.set(cookieConfig.name, responseToken, cookieConfig) 42 | 43 | // 删除代理响应的"X-Access-Token"http头 44 | delete ctx.response.headers[accessTokenHeaderName] 45 | delete ctx.response.headers[accessOriginHeaderName] 46 | }, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * token处理 3 | * @type {string} 4 | */ 5 | const logger = require('./logger/koa-logger')('proxyMiddleWare') 6 | // 带token http头 7 | const accessTokenHeaderName = 'x-access-token' 8 | // 请求来源 http头 9 | const accessOriginHeaderName = 'x-access-origin' 10 | 11 | // 默认cookie配置 12 | const defaultCookieConfig = { 13 | name: '_atk', 14 | httpOnly: true, 15 | overwrite: true, 16 | // 长期有效(20年) 17 | maxAge: 1000 * 60 * 60 * 24 * 365 * 20, 18 | } 19 | 20 | module.exports = function createRedis () { 21 | const cookieConfig = Object.assign({}, defaultCookieConfig) 22 | 23 | return { 24 | /** 25 | * 处理请求时的token操作 26 | * @param {ctx} ctx - koa ctx 27 | * @return {Object} - 需要添加的header头 28 | */ 29 | async handleRequest(ctx) { 30 | return { 31 | [accessOriginHeaderName]: ctx.query.accessOrigin || 'WAP', 32 | } 33 | }, 34 | /** 35 | * 处理响应时的token操作 36 | * @param {ctx} ctx - koa ctx 37 | */ 38 | async handleResponse(ctx) { 39 | logger.info('HandleResponse headers:', ctx.response.headers) 40 | const responseToken = ctx.response.headers[accessTokenHeaderName] 41 | // 如果后端响应头里没有token,则不设置cookie 42 | if (!responseToken) { 43 | return 44 | } 45 | logger.info(`Token found: ${responseToken}', it will be set to cookie.`) 46 | // 这里koa-better-http-proxy已经把代理响应头复制到原始响应头了 47 | ctx.cookies.set(cookieConfig.name, responseToken, cookieConfig) 48 | 49 | // 删除代理响应的"X-Access-Token"http头 50 | delete ctx.response.headers[accessTokenHeaderName] 51 | delete ctx.response.headers[accessOriginHeaderName] 52 | }, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * token处理 3 | * @type {string} 4 | */ 5 | const logger = require('./logger/koa-logger')('proxyMiddleWare') 6 | // 带token http头 7 | const accessTokenHeaderName = 'x-access-token' 8 | // 请求来源 http头 9 | const accessOriginHeaderName = 'x-access-origin' 10 | 11 | // 默认cookie配置 12 | const defaultCookieConfig = { 13 | name: '_atk', 14 | httpOnly: true, 15 | overwrite: true, 16 | // 长期有效(20年) 17 | maxAge: 1000 * 60 * 60 * 24 * 365 * 20, 18 | } 19 | 20 | module.exports = function createRedis () { 21 | const cookieConfig = Object.assign({}, defaultCookieConfig) 22 | 23 | return { 24 | /** 25 | * 处理请求时的token操作 26 | * @param {ctx} ctx - koa ctx 27 | * @return {Object} - 需要添加的header头 28 | */ 29 | async handleRequest(ctx) { 30 | return { 31 | [accessOriginHeaderName]: ctx.query.accessOrigin || 'WAP', 32 | } 33 | }, 34 | /** 35 | * 处理响应时的token操作 36 | * @param {ctx} ctx - koa ctx 37 | */ 38 | async handleResponse(ctx) { 39 | logger.info('HandleResponse headers:', ctx.response.headers) 40 | const responseToken = ctx.response.headers[accessTokenHeaderName] 41 | // 如果后端响应头里没有token,则不设置cookie 42 | if (!responseToken) { 43 | return 44 | } 45 | logger.info(`Token found: ${responseToken}', it will be set to cookie.`) 46 | // 这里koa-better-http-proxy已经把代理响应头复制到原始响应头了 47 | ctx.cookies.set(cookieConfig.name, responseToken, cookieConfig) 48 | 49 | // 删除代理响应的"X-Access-Token"http头 50 | delete ctx.response.headers[accessTokenHeaderName] 51 | delete ctx.response.headers[accessOriginHeaderName] 52 | }, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/6. 3 | */ 4 | const webpack = require('webpack') 5 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 6 | 7 | const config = require('./webpack.config.base')('dev') 8 | const postcss = require('./postcss.conf')() 9 | 10 | // cheap-module-eval-source-map is faster for development 11 | config.devtool = '#cheap-module-source-map' 12 | 13 | // add hot-reload related code to entry chunks 14 | Object.keys(config.entry).forEach(function (name) { 15 | config.entry[name] = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true'].concat(config.entry[name]) 16 | }) 17 | 18 | config.module.rules.push( 19 | { 20 | test: /\.css$/, 21 | use: ['style-loader', 'css-loader', { 22 | loader: 'postcss-loader', 23 | options: { plugins: postcss, sourceMap: 'inline' } 24 | }], 25 | }, 26 | { 27 | test: /\.(styl|stylus)$/, 28 | use: ['style-loader', 'css-loader', { 29 | loader: 'postcss-loader', 30 | options: { plugins: postcss, sourceMap: 'inline' } 31 | }, 32 | 'stylus-loader' 33 | ], 34 | } 35 | ) 36 | config.plugins = (config.plugins || []).concat([ 37 | //你可以理解为,通过配置了DefinePlugin,那么这里面的标识就相当于全局变量,你的业务代码可以直接使用配置的标识。 38 | new webpack.DefinePlugin({ 39 | 'process.env': { 40 | NODE_ENV: '"development"', 41 | VUE_ENV: '"client"', 42 | }, 43 | }), 44 | // new webpack.optimize.MinChunkSizePlugin({ 45 | // minChunkSize: 100000 // Minimum number of characters 46 | // }), 47 | // 全局开启代码热替换 48 | new webpack.HotModuleReplacementPlugin(), 49 | new webpack.NoEmitOnErrorsPlugin(), 50 | new FriendlyErrorsPlugin(), 51 | ]) 52 | 53 | module.exports = config 54 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack server配置 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const config = require('./webpack.config.base')() 8 | const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') 9 | const ExtractCssChunks = require("extract-css-chunks-webpack-plugin") 10 | 11 | module.exports = merge(config, { 12 | // 设置代码调试map 13 | devtool: false, 14 | mode: 'production', 15 | optimization: { 16 | runtimeChunk: { 17 | name: 'ml-node' 18 | }, 19 | splitChunks: { 20 | cacheGroups: { 21 | commons: { 22 | chunks: 'initial', 23 | minChunks: 5, 24 | }, 25 | vendor: { 26 | chunks: 'all', 27 | name: 'vendor', 28 | test: /node_modules/, 29 | priority: -10, 30 | reuseExistingChunk: false, 31 | }, 32 | }, 33 | }, 34 | }, 35 | plugins: [ 36 | new webpack.DefinePlugin({ 37 | 'process.env': { 38 | NODE_ENV: JSON.stringify("production"), 39 | }, 40 | }), 41 | new ExtractCssChunks({ 42 | filename: 'assets/css/[name].[chunkhash:8].css', 43 | chunkFilename: 'assets/css/[id].[chunkhash:8].css', 44 | }), 45 | // 限制文件最小KB 46 | new webpack.optimize.MinChunkSizePlugin({ 47 | minChunkSize: 20000 48 | }), 49 | new OptimizeCssAssetsPlugin( 50 | { 51 | cssProcessor: require('cssnano'), 52 | cssProcessorOptions: { 53 | // postcss那边已经处理过autoprefixer了,这里把它关掉,否则会导致浏览器前缀兼容范围问题 54 | autoprefixer: false, 55 | discardComments: {removeAll: true} 56 | }, 57 | } 58 | ),] 59 | }) 60 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/httpMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * http中间件 3 | * 为ctx添加http方法, 然后在后续的路由中, ctx.http.get(url: '/url') 即可 4 | */ 5 | const axios = require('axios') 6 | 7 | const methods = ['get', 'post', 'put', 'delete'] 8 | 9 | /** 10 | * 默认请求头 11 | */ 12 | const defaultHeaders = { 13 | Accept: 'application/json, text/plain, */*; charset=utf-8', 14 | 'Content-Type': 'application/json; charset=utf-8', 15 | Pragma: 'no-cache', 16 | 'Cache-Control': 'no-cache', 17 | } 18 | 19 | const axiosInstance = axios.create({ 20 | timeout: 20 * 1000, 21 | headers: defaultHeaders, 22 | }) 23 | 24 | // http request 拦截器 25 | axiosInstance.interceptors.request.use( 26 | (config) => { 27 | config._reqeustStartTimestamp = Date.now() 28 | return config 29 | }, 30 | (error) => { 31 | return Promise.reject(error) 32 | } 33 | ) 34 | 35 | // http response 拦截器 36 | axiosInstance.interceptors.response.use( 37 | (response) => { 38 | return response 39 | }, 40 | (error) => { 41 | return Promise.reject(error) 42 | } 43 | ) 44 | 45 | /** 46 | * @returns {Function} ctx function 47 | */ 48 | module.exports = function () { 49 | return function httpMiddleware (ctx, next) { 50 | const http = {} 51 | methods.forEach(method => { 52 | http[method] = (...args) => { 53 | let config 54 | const emptyConfig = { headers: {} } 55 | // axios的get和delete方法木有body,只能接受两个参数 56 | if (method === 'get' || method === 'delete') { 57 | config = args[1] = args[1] || emptyConfig 58 | } else { 59 | config = args[2] = args[2] || emptyConfig 60 | } 61 | // 把浏览器的cookie的带上 62 | config.headers.cookie = ctx.req.headers.cookie || '' 63 | return axiosInstance[method](...args) 64 | } 65 | }) 66 | ctx.http = http 67 | return next() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/koa-prod-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/13. 3 | */ 4 | const Koa = require('koa') 5 | const KoaRouter = require('koa-router')() 6 | const currentIP = require('ip').address() 7 | 8 | const appConfig = require('./../app.config') 9 | 10 | const loggerMiddleware = require('koa-logger')() 11 | const errorMiddleware = require('./utils/errorMiddleWare') 12 | const staticMiddleWare = require('./utils/staticMiddleWare') 13 | const setCookieMiddleware = require('./utils/setCookieMiddleWare') 14 | const httpMiddleware = require('./utils/httpMiddleWare') 15 | const spaMiddleWare = require('./utils/spaMiddleWare') 16 | const proxyMiddleware = require('./utils/proxyMiddleWare') 17 | 18 | const app = new Koa() 19 | const uri = 'http://' + currentIP + ':' + appConfig.appPort 20 | 21 | // 中间件,一组async函数,generator函数需要convert转换 22 | const middleWares = [ 23 | // 打印请求与响应 日志 24 | loggerMiddleware, 25 | // 静态资源中间件 26 | staticMiddleWare(), 27 | // 压缩响应 28 | require('koa-compress')(), 29 | // 错误处理 30 | errorMiddleware, 31 | // 手动设置cookie方法 32 | setCookieMiddleware, 33 | // http中间件 34 | httpMiddleware(), 35 | // spa单页应用处理,非api后段请求返回index.html 36 | spaMiddleWare(), 37 | // 插入自定义中间件 38 | ...appConfig.middleWares, 39 | // 路由 40 | KoaRouter.middleware(), 41 | // 代理中间件 42 | proxyMiddleware(), 43 | ] 44 | 45 | middleWares.forEach((middleware) => { 46 | if (!middleware) { 47 | return 48 | } 49 | app.use(middleware) 50 | }) 51 | 52 | console.log('> Starting production server address >>> ' + uri) 53 | // 错误处理 54 | app.on('error', (err) => { 55 | console.error('Server error: \n%s\n%s ', err.stack || '') 56 | }) 57 | 58 | const server = app.listen(appConfig.appPort) 59 | 60 | process.on('SIGTERM', () => { 61 | console.log('Stopping dev server') 62 | devMiddleware.close() 63 | server.close(() => { 64 | process.exit(0) 65 | }) 66 | }) -------------------------------------------------------------------------------- /webpack4-ssr-config/client/entry-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 运行于浏览器 3 | * Created by zdliuccit on 2018/7/6. 4 | * */ 5 | import Vue from 'vue' 6 | 7 | import { createApp } from './index' 8 | import ProgressBar from './components/ProgressBar.vue' 9 | // 引入http请求 10 | import http from './../config/http/http' 11 | // global progress bar 12 | const bar = Vue.prototype.$bar = new Vue(ProgressBar).$mount() 13 | document.body.appendChild(bar.$el) 14 | 15 | // a global mixin that calls `asyncData` when a route component's params change 16 | Vue.mixin({ 17 | beforeRouteUpdate(to, from, next) { 18 | const { asyncData } = this.$options 19 | if (asyncData) { 20 | asyncData({ store: this.$store, route: to }) 21 | .then(next) 22 | .catch(next) 23 | } else { 24 | next() 25 | } 26 | } 27 | }) 28 | 29 | const { app, router, store } = createApp() 30 | 31 | // prime the store with server-initialized state. 32 | // the state is determined during SSR and inlined in the page markup. 33 | if (window.__INITIAL_STATE__) { 34 | store.replaceState(window.__INITIAL_STATE__) 35 | // 客户端和服务端保持一致 36 | store.state.$http = http 37 | } 38 | 39 | router.onReady(() => { 40 | router.beforeResolve((to, from, next) => { 41 | const matched = router.getMatchedComponents(to) 42 | const prevMatched = router.getMatchedComponents(from) 43 | let diffed = false 44 | const activated = matched.filter((c, i) => { 45 | return diffed || (diffed = (prevMatched[i] !== c)) 46 | }) 47 | const asyncDataHooks = activated.map(c => c.asyncData).filter(_ => _) 48 | if (!asyncDataHooks.length) { 49 | return next() 50 | } 51 | bar.start() 52 | Promise.all(asyncDataHooks.map(hook => hook({ store, router, route: to }))) 53 | .then(() => { 54 | bar.finish() 55 | next() 56 | }) 57 | .catch(next) 58 | }) 59 | 60 | app.$mount('#app') 61 | }) -------------------------------------------------------------------------------- /webpack4-ssr-config/client/entry-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 运行于服务器 3 | * Created by zdliuccit on 2018/7/6. 4 | * */ 5 | 6 | import { createApp } from './index' 7 | 8 | // 引入http请求 9 | import http from './../config/http/http' 10 | // 处理ssr期间cookies穿透 11 | import { setCookies } from './../config/http/http' 12 | 13 | const { app } = createApp() 14 | 15 | // 这里假定 App.vue 模板中根元素具有 `id="app"` 16 | app.$mount('#app') 17 | 18 | export default context => { 19 | // 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise, 20 | // 以便服务器能够等待所有的内容在渲染前, 21 | // 就已经准备就绪。 22 | return new Promise((resolve, reject) => { 23 | const { app, router, store } = createApp() 24 | 25 | const { url } = context 26 | const { fullPath } = router.resolve(url).route 27 | 28 | if (fullPath !== url) { 29 | return reject({ url: fullPath }) 30 | } 31 | 32 | // 设置服务器端 router 的位置,路由配置里如果设置过base,url需要把url.replace(base,'')掉,不然会404 33 | router.push(url) 34 | 35 | // 等到 router 将可能的异步组件和钩子函数解析完 36 | router.onReady(() => { 37 | // 获取该url路由下的所有Component,这些组件定义在Vue Router中。 38 | const matchedComponents = router.getMatchedComponents() 39 | // 匹配不到的路由,执行 reject 函数,并返回 404 40 | if (!matchedComponents.length) { 41 | return reject({ code: 404 }) 42 | } 43 | // SSR期间同步cookies 44 | setCookies(context.cookies || {}) 45 | // http注入到rootState上,方便store里调用 46 | store.state.$http = http 47 | // 使用Promise.all执行匹配到的Component的asyncData方法,即预取数据 48 | Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({ 49 | store, 50 | router, 51 | route: router.currentRoute, 52 | }))).then(() => { 53 | // 在所有预取钩子(preFetch hook) resolve 后, 54 | // 我们的 store 现在已经填充入渲染应用程序所需的状态。 55 | // 当我们将状态附加到上下文, 56 | // 并且 `template` 选项用于 renderer 时, 57 | // 状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。 58 | context.state = store.state 59 | resolve(app) 60 | }).catch(reject) 61 | }, reject) 62 | }) 63 | } -------------------------------------------------------------------------------- /webpack4-ssr-config/client/views/home.vue: -------------------------------------------------------------------------------- 1 | 18 | 23 | -------------------------------------------------------------------------------- /webpack3-basic-config/client/view/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 47 | 71 | 78 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/6. 3 | */ 4 | const path = require('path') 5 | const webpack = require('webpack') 6 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 7 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 8 | const config = require('./webpack.config.base')('prod') 9 | const postcss = require('./postcss.conf')() 10 | 11 | config.output.filename = '[name].[chunkhash:7].js' 12 | config.output.chunkFilename = '[id].[chunkhash:7].js' 13 | 14 | config.devtool = false 15 | 16 | config.module.rules.push( 17 | { 18 | test: /\.css$/, 19 | use: ExtractTextPlugin.extract({ 20 | use: ['css-loader', { loader: 'postcss-loader', options: { plugins: postcss } }], 21 | fallback: 'style-loader', 22 | }), 23 | }, 24 | { 25 | test: /\.styl$/, 26 | use: ExtractTextPlugin.extract({ 27 | use: ['css-loader', { loader: 'postcss-loader', options: { plugins: postcss } }, 'stylus-loader'], 28 | fallback: 'style-loader', 29 | }), 30 | } 31 | ) 32 | 33 | config.plugins = (config.plugins || []).concat([ 34 | new webpack.LoaderOptionsPlugin({ 35 | // webpack 2.0之后,这边不配置px转rem不会成功!!!蛋疼 36 | options: { 37 | postcss: postcss 38 | }, 39 | }), 40 | // 定义全局常量 41 | new webpack.DefinePlugin({ 42 | 'process.env': { 43 | //注意一个单引号一个双引号…… 这里是要将 "production" 替换到文件里面 44 | NODE_ENV: JSON.stringify("production"), 45 | VUE_ENV: JSON.stringify("client"), 46 | }, 47 | }), 48 | // 合并公共模块为单独文件 49 | new webpack.optimize.CommonsChunkPlugin({ 50 | name: 'vendor', 51 | filename: 'vendor-[hash].min.js', 52 | }), 53 | // js压缩 54 | new webpack.optimize.UglifyJsPlugin({ 55 | comments: false, // 去掉注释 56 | compress: { 57 | warnings: false, // 不显示警告 58 | drop_console: false, 59 | }, 60 | }), 61 | // 分离css文件 62 | new ExtractTextPlugin('[name].[contenthash:8].css'), 63 | 64 | // optimize \ minimize CSS assets 65 | new OptimizeCSSPlugin({ 66 | cssProcessorOptions: { 67 | safe: true, 68 | // postcss那边已经处理过autoprefixer了,这里把它关掉,否则会导致浏览器前缀兼容范围问题 69 | autoprefixer: false, 70 | }, 71 | }), 72 | ]) 73 | 74 | module.exports = config 75 | -------------------------------------------------------------------------------- /react-base-webpack/config/koa.server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * koa2 server 入口 3 | * Created by zdliuccit on 2018/11/1. 4 | */ 5 | const Koa = require('koa') 6 | const convert = require('koa-convert') 7 | const webpack = require('webpack') 8 | const merge = require('webpack-merge') 9 | 10 | const KoaRouter = require('koa-router')() 11 | const koaCompress = require('koa-compress')() 12 | const loggerMiddleware = require('koa-logger')() 13 | const errorMiddleware = require('./middle/errorMiddleWare') 14 | const proxyMiddleware = require('./middle/proxyMiddleWare') 15 | const spaMiddleWare = require('./middle/spaMiddleWare') 16 | const webpackDevMiddleware = require('koa-webpack-dev-middleware') 17 | const webpackHotMiddleware = require('koa-webpack-hot-middleware') 18 | 19 | const opn = require('opn') 20 | const config = merge(require('./webpack.config.dev')) 21 | const appConfig = require('./../app.config') 22 | const currentIP = require('ip').address() 23 | const uri = `http://${currentIP}:${appConfig.appPort}` 24 | const clientCompiler = webpack(config) 25 | const devMiddleware = webpackDevMiddleware(clientCompiler, { 26 | publicPath: config.output.publicPath, 27 | headers: {'Access-Control-Allow-Origin': '*'}, 28 | stats: { 29 | colors: true, 30 | modules: false, 31 | }, 32 | noInfo: false, 33 | }) 34 | // koa server 35 | const app = new Koa() 36 | 37 | // 中间件,一组async函数,generator函数需要convert转换 38 | const middleWares = [ 39 | // 打印请求与响应 日志 40 | loggerMiddleware, 41 | // 压缩响应 42 | koaCompress, 43 | // 错误处理 44 | errorMiddleware, 45 | // webpack开发中间件 46 | convert(devMiddleware), 47 | // webpack热替换中间件 48 | convert(webpackHotMiddleware(clientCompiler)), 49 | // spa单页应用处理,非api后段请求返回index.html 50 | spaMiddleWare(), 51 | // 路由 52 | KoaRouter.middleware(), 53 | // 代理中间件 54 | proxyMiddleware(), 55 | ] 56 | 57 | middleWares.forEach((middleware) => { 58 | if (!middleware) return 59 | app.use(middleware) 60 | }) 61 | 62 | console.log('> Starting dev server...') 63 | 64 | devMiddleware.waitUntilValid(() => { 65 | console.log('> Listening at ' + uri + '\n') 66 | // opn(uri) 67 | }) 68 | 69 | // 错误处理 70 | app.on('error', (err) => { 71 | console.error('Server error: \n%s\n%s ', err.stack || '') 72 | }) 73 | 74 | app.listen(appConfig.appPort) 75 | 76 | -------------------------------------------------------------------------------- /react-base-webpack/config/middle/spaMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2018/11/1. 3 | * 基于 https://github.com/bripkens/connect-history-api-fallback 改造 4 | */ 5 | const path = require('path') 6 | const fs = require('fs') 7 | const logger = require('./../logger/koa-logger')('spaMiddleWare') 8 | const currentIP = require('ip').address() 9 | 10 | const IS_DEBUG = true 11 | const appConfig = require('./../../app.config') 12 | 13 | const defaultOptions = { include: /^\/(api|static|public|v3)/ } 14 | 15 | /** 16 | * 读取构建过的文件,public目录下 17 | * @param {String} filename 文件名 18 | * @return {String} 文件内容 19 | */ 20 | function readBuiltFile(filename) { 21 | return fs.readFileSync(path.join(process.cwd(), 'dist', filename), 'utf-8') 22 | } 23 | 24 | let indexHTML 25 | 26 | // 生产模式 27 | if (!IS_DEBUG) { 28 | indexHTML = readBuiltFile('index.html') 29 | } 30 | 31 | /** 32 | * 单页应用中间件 33 | * @param {Object} options 配置项 34 | * @return {function} 中间件 35 | */ 36 | module.exports = function (options) { 37 | options = Object.assign({}, defaultOptions, options) 38 | return async function spa(ctx, next) { 39 | if (!options.include.test(ctx.url)) { 40 | /** 41 | * 开发模式从koa2服务中获取index 42 | */ 43 | await new Promise((resolve) => { 44 | if (indexHTML && !IS_DEBUG) { 45 | resolve() 46 | } else { 47 | require('http').get('http://' + currentIP + ':' + appConfig.appPort, (res) => { 48 | res.on('data', (chunk) => { 49 | logger.info('Fetching index.html succeed.') 50 | indexHTML = chunk.toString('utf-8') 51 | resolve() 52 | }) 53 | }).on('error', (e) => { 54 | logger.error(`Fetching index.html error: ${e.message}`) 55 | process.exit(1) 56 | }) 57 | } 58 | }).then(doRender) 59 | 60 | /** 61 | * 返回HTML 62 | */ 63 | function doRender() { 64 | const res = ctx.res 65 | res.statusCode = 200 66 | // 这句很重要,否则会影响到weinre调试 67 | res.setHeader('Content-Type', 'text/html; charset=utf-8') 68 | res.end(`${indexHTML}`) 69 | logger.info('Page routing request') 70 | } 71 | } else { 72 | return next() 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/spaMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 基于 https://github.com/bripkens/connect-history-api-fallback 改造 3 | */ 4 | const path = require('path') 5 | const fs = require('fs') 6 | const logger = require('./logger/koa-logger')('spaMiddleWare') 7 | const currentIP = require('ip').address() 8 | 9 | const {IS_DEBUG} = require('../utils/env') 10 | const appConfig = require('./../../app.config') 11 | 12 | const defaultOptions = {include: /^\/(api|static|public|v3)/} 13 | 14 | /** 15 | * 读取构建过的文件,public目录下 16 | * @param {String} filename 文件名 17 | * @return {String} 文件内容 18 | */ 19 | function readBuiltFile(filename) { 20 | return fs.readFileSync(path.join(process.cwd(), 'public', filename), 'utf-8') 21 | } 22 | 23 | let indexHTML 24 | 25 | // 生产模式 26 | if (!IS_DEBUG) { 27 | indexHTML = readBuiltFile('index.html') 28 | } 29 | 30 | /** 31 | * 单页应用中间件 32 | * @param {Object} options 配置项 33 | * @return {function} 中间件 34 | */ 35 | module.exports = function (options) { 36 | options = Object.assign({}, defaultOptions, options) 37 | return async function spa(ctx, next) { 38 | if (!options.include.test(ctx.url)) { 39 | /** 40 | * 开发模式从koa2服务中获取index 41 | */ 42 | await new Promise((resolve) => { 43 | if (indexHTML && !IS_DEBUG) { 44 | resolve() 45 | } else { 46 | require('http').get('http://' + currentIP + ':' + appConfig.appPort, (res) => { 47 | res.on('data', (chunk) => { 48 | logger.info('Fetching index.html succeed.') 49 | indexHTML = chunk.toString('utf-8') 50 | resolve() 51 | }) 52 | }).on('error', (e) => { 53 | logger.error(`Fetching index.html error: ${e.message}`) 54 | process.exit(1) 55 | }) 56 | } 57 | }).then(doRender) 58 | 59 | /** 60 | * 返回HTML 61 | */ 62 | function doRender() { 63 | const res = ctx.res 64 | res.statusCode = 200 65 | // 这句很重要,否则会影响到weinre调试 66 | res.setHeader('Content-Type', 'text/html; charset=utf-8') 67 | res.end(`${indexHTML}`) 68 | logger.info('Page routing request') 69 | return 70 | } 71 | } else { 72 | return next() 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/spaMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 基于 https://github.com/bripkens/connect-history-api-fallback 改造 3 | */ 4 | const path = require('path') 5 | const fs = require('fs') 6 | const logger = require('./logger/koa-logger')('spaMiddleWare') 7 | const currentIP = require('ip').address() 8 | 9 | const {IS_DEBUG} = require('../utils/env') 10 | const appConfig = require('./../../app.config') 11 | 12 | const defaultOptions = {include: /^\/(api|static|public|v3)/} 13 | 14 | /** 15 | * 读取构建过的文件,public目录下 16 | * @param {String} filename 文件名 17 | * @return {String} 文件内容 18 | */ 19 | function readBuiltFile(filename) { 20 | return fs.readFileSync(path.join(process.cwd(), 'public', filename), 'utf-8') 21 | } 22 | 23 | let indexHTML 24 | 25 | // 生产模式 26 | if (!IS_DEBUG) { 27 | indexHTML = readBuiltFile('index.html') 28 | } 29 | 30 | /** 31 | * 单页应用中间件 32 | * @param {Object} options 配置项 33 | * @return {function} 中间件 34 | */ 35 | module.exports = function (options) { 36 | options = Object.assign({}, defaultOptions, options) 37 | return async function spa(ctx, next) { 38 | if (!options.include.test(ctx.url)) { 39 | /** 40 | * 开发模式从koa2服务中获取index 41 | */ 42 | await new Promise((resolve) => { 43 | if (indexHTML && !IS_DEBUG) { 44 | resolve() 45 | } else { 46 | require('http').get('http://' + currentIP + ':' + appConfig.appPort, (res) => { 47 | res.on('data', (chunk) => { 48 | logger.info('Fetching index.html succeed.') 49 | indexHTML = chunk.toString('utf-8') 50 | resolve() 51 | }) 52 | }).on('error', (e) => { 53 | logger.error(`Fetching index.html error: ${e.message}`) 54 | process.exit(1) 55 | }) 56 | } 57 | }).then(doRender) 58 | 59 | /** 60 | * 返回HTML 61 | */ 62 | function doRender() { 63 | const res = ctx.res 64 | res.statusCode = 200 65 | // 这句很重要,否则会影响到weinre调试 66 | res.setHeader('Content-Type', 'text/html; charset=utf-8') 67 | res.end(`${indexHTML}`) 68 | logger.info('Page routing request') 69 | return 70 | } 71 | } else { 72 | return next() 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/logger/vue-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/21. 3 | * 日志打印器 class 4 | */ 5 | import { IS_DEBUG } from './../env' 6 | 7 | class Logger { 8 | /** 9 | * 构造函数 10 | * @param filename 调用的文件名 11 | */ 12 | constructor (filename) { 13 | this.filename = filename 14 | } 15 | } 16 | 17 | /** 18 | * 定义方法 19 | * @type {{info: string, log: string, warn: string, error: string}} 20 | */ 21 | const methods = { 22 | log: 'color: green', 23 | info: 'color:#6495ED', 24 | warn: 'color: #cc33cc', 25 | error: 'color: red', 26 | } 27 | /** 28 | * 将方法绑定到原型上 29 | */ 30 | Object.entries(methods).forEach(([method, color]) => { 31 | Logger.prototype[method] = function (...args) { 32 | // 非生产环境 33 | if (!IS_DEBUG) { 34 | return 35 | } 36 | args.unshift(`%c[${this.filename}]:`, color) 37 | console[method](...args) 38 | } 39 | }) 40 | 41 | /** 42 | * 定义 VueLogger class 43 | */ 44 | class VueLogger { 45 | constructor (filename) { 46 | const logger = new Logger(filename) 47 | Object.keys(methods).forEach(method => { 48 | this[method] = (vm, ...args) => { 49 | // 不存在vue实例时,简单打印 50 | if (!vm) { 51 | return 52 | } 53 | if (vm._isVue !== true) { 54 | logger[method].call(logger, vm, ...args) 55 | return 56 | } 57 | // 组件当前__file 58 | const filePath = vm.$options._parentVnode.componentOptions.Ctor.options.__file 59 | // 截取组件名称 60 | const componentName = filePath.slice(filePath.lastIndexOf('/') + 1) || '(unkonwn component name)' 61 | // 当前路由路径 62 | const fullPath = vm.$route.fullPath || '(unkonwn route fullPath)' 63 | logger[method].call(logger, ...args, `@${componentName}`, `#${fullPath}`) 64 | } 65 | }) 66 | } 67 | } 68 | 69 | const vueLogger = new VueLogger('component') 70 | const componentLogger = {} 71 | /** 72 | * 暴露install钩子,供vue注册 73 | * @param {Vue} Vue - Vue构造器类 74 | */ 75 | componentLogger.install = function (Vue) { // 基础打印器 76 | Object.keys(methods).forEach((method) => { 77 | Vue.prototype[method] = function (...args) { 78 | vueLogger[method].call({}, this, ...args) 79 | } 80 | }) 81 | } 82 | 83 | export default componentLogger -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/logger/vue-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/9/21. 3 | * 日志打印器 class 4 | */ 5 | import { IS_DEBUG } from './../env' 6 | 7 | class Logger { 8 | /** 9 | * 构造函数 10 | * @param filename 调用的文件名 11 | */ 12 | constructor (filename) { 13 | this.filename = filename 14 | } 15 | } 16 | 17 | /** 18 | * 定义方法 19 | * @type {{info: string, log: string, warn: string, error: string}} 20 | */ 21 | const methods = { 22 | log: 'color: green', 23 | info: 'color:#6495ED', 24 | warn: 'color: #cc33cc', 25 | error: 'color: red', 26 | } 27 | /** 28 | * 将方法绑定到原型上 29 | */ 30 | Object.entries(methods).forEach(([method, color]) => { 31 | Logger.prototype[method] = function (...args) { 32 | // 非生产环境 33 | if (!IS_DEBUG) { 34 | return 35 | } 36 | args.unshift(`%c[${this.filename}]:`, color) 37 | console[method](...args) 38 | } 39 | }) 40 | 41 | /** 42 | * 定义 VueLogger class 43 | */ 44 | class VueLogger { 45 | constructor (filename) { 46 | const logger = new Logger(filename) 47 | Object.keys(methods).forEach(method => { 48 | this[method] = (vm, ...args) => { 49 | // 不存在vue实例时,简单打印 50 | if (!vm) { 51 | return 52 | } 53 | if (vm._isVue !== true) { 54 | logger[method].call(logger, vm, ...args) 55 | return 56 | } 57 | // 组件当前__file 58 | const filePath = vm.$options._parentVnode.componentOptions.Ctor.options.__file 59 | // 截取组件名称 60 | const componentName = filePath.slice(filePath.lastIndexOf('/') + 1) || '(unkonwn component name)' 61 | // 当前路由路径 62 | const fullPath = vm.$route.fullPath || '(unkonwn route fullPath)' 63 | logger[method].call(logger, ...args, `@${componentName}`, `#${fullPath}`) 64 | } 65 | }) 66 | } 67 | } 68 | 69 | const vueLogger = new VueLogger('component') 70 | const componentLogger = {} 71 | /** 72 | * 暴露install钩子,供vue注册 73 | * @param {Vue} Vue - Vue构造器类 74 | */ 75 | componentLogger.install = function (Vue) { // 基础打印器 76 | Object.keys(methods).forEach((method) => { 77 | Vue.prototype[method] = function (...args) { 78 | vueLogger[method].call({}, this, ...args) 79 | } 80 | }) 81 | } 82 | 83 | export default componentLogger -------------------------------------------------------------------------------- /webpack4-ssr-config/config/logger/vue-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zdliuccit on 2017/9/21. 3 | * 日志打印器 class 4 | */ 5 | const IS_DEBUG = process.env.NODE_ENV !== 'production' 6 | 7 | class Logger { 8 | /** 9 | * 构造函数 10 | * @param filename 调用的文件名 11 | */ 12 | constructor(filename) { 13 | this.filename = filename 14 | } 15 | } 16 | 17 | /** 18 | * 定义方法 19 | * @type {{info: string, log: string, warn: string, error: string}} 20 | */ 21 | const methods = { 22 | log: 'color: green', 23 | info: 'color:#6495ED', 24 | warn: 'color: #cc33cc', 25 | error: 'color: red', 26 | } 27 | /** 28 | * 将方法绑定到原型上 29 | */ 30 | Object.entries(methods).forEach(([method, color]) => { 31 | Logger.prototype[method] = function (...args) { 32 | // 非生产环境 33 | if (!IS_DEBUG) { 34 | return 35 | } 36 | args.unshift(`%c[${this.filename}]:`, color) 37 | console[method](...args) 38 | } 39 | }) 40 | 41 | /** 42 | * 定义 VueLogger class 43 | */ 44 | class VueLogger { 45 | constructor(filename) { 46 | const logger = new Logger(filename) 47 | Object.keys(methods).forEach(method => { 48 | this[method] = (vm, ...args) => { 49 | // 不存在vue实例时,简单打印 50 | if (!vm) { 51 | return 52 | } 53 | if (vm._isVue !== true) { 54 | logger[method].call(logger, vm, ...args) 55 | return 56 | } 57 | // 组件当前__file 58 | const filePath = vm.$options._parentVnode.componentOptions.Ctor.options.__file 59 | // 截取组件名称 60 | const componentName = filePath.slice(filePath.lastIndexOf('/') + 1) || '(unkonwn component name)' 61 | // 当前路由路径 62 | const fullPath = vm.$route.fullPath || '(unkonwn route fullPath)' 63 | logger[method].call(logger, ...args, `@${componentName}`, `#${fullPath}`) 64 | } 65 | }) 66 | } 67 | } 68 | 69 | const vueLogger = new VueLogger('component') 70 | const componentLogger = {} 71 | /** 72 | * 暴露install钩子,供vue注册 73 | * @param {Vue} Vue - Vue构造器类 74 | */ 75 | componentLogger.install = function (Vue) { // 基础打印器 76 | Object.keys(methods).forEach((method) => { 77 | Vue.prototype[method] = function (...args) { 78 | vueLogger[method].call({}, this, ...args) 79 | } 80 | }) 81 | } 82 | 83 | export default componentLogger -------------------------------------------------------------------------------- /webpack4-basic-config/config/koa-dev-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/13. 3 | */ 4 | const Koa = require('koa') 5 | const KoaRouter = require('koa-router')() 6 | const webpack = require('webpack') 7 | const currentIP = require('ip').address() 8 | 9 | const opn = require('opn') 10 | const loggerMiddleware = require('koa-logger')() 11 | const convert = require('koa-convert') 12 | const webpackDevMiddleware = require('koa-webpack-dev-middleware') 13 | const webpackHotMiddleware = require('koa-webpack-hot-middleware') 14 | 15 | const appConfig = require('./../app.config') 16 | const config = require('./webpack.config.dev') 17 | const clientCompiler = webpack(config) 18 | 19 | const proxyMiddleware = require('./utils/proxyMiddleWare') 20 | const errorMiddleware = require('./utils/errorMiddleWare') 21 | const spaMiddleWare = require('./utils/spaMiddleWare') 22 | const staticMiddleWare = require('./utils/staticMiddleWare') 23 | 24 | const app = new Koa() 25 | const uri = 'http://' + currentIP + ':' + appConfig.appPort 26 | 27 | const devMiddleware = webpackDevMiddleware(clientCompiler, { 28 | publicPath: config.output.publicPath, 29 | headers: {'Access-Control-Allow-Origin': '*'}, 30 | stats: { 31 | colors: true, 32 | modules: false, 33 | }, 34 | noInfo: false, 35 | }) 36 | 37 | // 中间件,一组async函数,generator函数需要convert转换 38 | const middleWares = [ 39 | // 打印请求与响应 日志 40 | loggerMiddleware, 41 | // 压缩响应 42 | require('koa-compress')(), 43 | // 错误处理 44 | errorMiddleware, 45 | // 资源中间件 46 | staticMiddleWare(), 47 | // webpack开发中间件 48 | convert(devMiddleware), 49 | // webpack热替换中间件 50 | convert(webpackHotMiddleware(clientCompiler)), 51 | // spa单页应用处理,非api后段请求返回index.html 52 | spaMiddleWare(), 53 | // 路由 54 | KoaRouter.middleware(), 55 | // 代理中间件 56 | proxyMiddleware(), 57 | ] 58 | 59 | middleWares.forEach((middleware) => { 60 | if (!middleware) { 61 | return 62 | } 63 | app.use(middleware) 64 | }) 65 | 66 | console.log('> Starting dev server...') 67 | 68 | devMiddleware.waitUntilValid(() => { 69 | console.log('> Listening at ' + uri + '\n') 70 | opn(uri) 71 | }) 72 | 73 | // 错误处理 74 | app.on('error', (err) => { 75 | console.error('Server error: \n%s\n%s ', err.stack || '') 76 | }) 77 | 78 | app.listen(appConfig.appPort) 79 | -------------------------------------------------------------------------------- /react-base-webpack/config/webpack.config.base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack base配置 3 | * Created by zdliuccit on 2018/11/1. 4 | */ 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin') 8 | const HtmlWebpackPlugin = require('html-webpack-plugin') 9 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 10 | 11 | const isProd = process.env.NODE_ENV === 'production' 12 | const appConfig = require('./../app.config') 13 | const appVersion = new Date().getTime() 14 | 15 | function resolve(dir) { 16 | return path.resolve(process.cwd(), dir) 17 | } 18 | 19 | const favicon = path.join(process.cwd(), 'favicon.ico') 20 | 21 | module.exports = function () { 22 | const config = { 23 | output: { 24 | path: resolve('dist'), 25 | filename: `[name].[${isProd ? 'chunkhash' : 'hash'}:8].js`, 26 | chunkFilename: '[id].js', 27 | publicPath: '/' 28 | }, 29 | resolve: { 30 | extensions: ['.js', '.jsx', '.json', '.scss'], 31 | alias: { 32 | '@': resolve('client'), 33 | } 34 | }, 35 | module: { 36 | rules: [ 37 | // js,jsx 转译 38 | { 39 | test: /\.(js|jsx)$/, 40 | use: ['babel-loader'], 41 | exclude: /(node_modules|bower_components)/, 42 | }, 43 | { 44 | test: /\.json$/, 45 | use: 'json-loader', 46 | }, 47 | { 48 | test: /\.(gif|jpg|jpeg|png|bmp|svg|ico)(\?.*)?$/, 49 | use: [{ 50 | loader: 'url-loader', 51 | options: { 52 | limit: 1, 53 | name: 'assets/images/[name].[hash:8].[ext]', 54 | }, 55 | }], 56 | }, 57 | { 58 | test: /\.(woff|woff2|eot|ttf)(\?.*)?$/, 59 | use: [{ 60 | loader: 'url-loader', 61 | options: { 62 | limit: 8912, 63 | name: 'assets/font/[name].[hash:8].[ext]', 64 | }, 65 | }], 66 | }, 67 | ], 68 | }, 69 | plugins: [ 70 | new CaseSensitivePathsPlugin(), 71 | new HtmlWebpackPlugin({ 72 | appVersion, 73 | favicon, 74 | filename: 'index.html', 75 | template: path.join(process.cwd(), 'index.template.ejs'), 76 | }), 77 | new FriendlyErrorsPlugin(), 78 | new webpack.optimize.LimitChunkCountPlugin({ 79 | maxChunks: 1 80 | }) 81 | ], 82 | } 83 | return config 84 | } -------------------------------------------------------------------------------- /webpack3-basic-config/config/koa-dev-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liuzhengdong on 2017/7/13. 3 | */ 4 | const Koa = require('koa') 5 | const KoaRouter = require('koa-router')() 6 | const webpack = require('webpack') 7 | const currentIP = require('ip').address() 8 | 9 | const opn = require('opn') 10 | const loggerMiddleware = require('koa-logger')() 11 | const convert = require('koa-convert') 12 | const webpackDevMiddleware = require('koa-webpack-dev-middleware') 13 | const webpackHotMiddleware = require('koa-webpack-hot-middleware') 14 | 15 | const appConfig = require('./../app.config') 16 | const config = require('./webpack.config.dev') 17 | const clientCompiler = webpack(config) 18 | 19 | const setCookieMiddleware = require('./utils/setCookieMiddleWare') 20 | const httpMiddleware = require('./utils/httpMiddleWare') 21 | const proxyMiddleware = require('./utils/proxyMiddleWare') 22 | const errorMiddleware = require('./utils/errorMiddleWare') 23 | const spaMiddleWare = require('./utils/spaMiddleWare') 24 | 25 | const app = new Koa() 26 | const uri = 'http://' + currentIP + ':' + appConfig.appPort 27 | 28 | const devMiddleware = webpackDevMiddleware(clientCompiler, { 29 | publicPath: config.output.publicPath, 30 | headers: { 'Access-Control-Allow-Origin': '*' }, 31 | stats: { 32 | colors: true, 33 | modules: false, 34 | }, 35 | noInfo: false, 36 | }) 37 | 38 | // 中间件,一组async函数,generator函数需要convert转换 39 | const middleWares = [ 40 | // 打印请求与响应 日志 41 | loggerMiddleware, 42 | // 压缩响应 43 | require('koa-compress')(), 44 | // 错误处理 45 | errorMiddleware, 46 | // webpack开发中间件 47 | convert(devMiddleware), 48 | // webpack热替换中间件 49 | convert(webpackHotMiddleware(clientCompiler)), 50 | // 手动设置cookie方法 51 | setCookieMiddleware, 52 | // http中间件 53 | httpMiddleware(), 54 | // spa单页应用处理,非api后段请求返回index.html 55 | spaMiddleWare(), 56 | // 插入自定义中间件 57 | ...appConfig.middleWares, 58 | // 路由 59 | KoaRouter.middleware(), 60 | // 代理中间件 61 | proxyMiddleware(), 62 | ] 63 | 64 | middleWares.forEach((middleware) => { 65 | if (!middleware) { 66 | return 67 | } 68 | app.use(middleware) 69 | }) 70 | 71 | console.log('> Starting dev server...') 72 | 73 | devMiddleware.waitUntilValid(() => { 74 | console.log('> Listening at ' + uri + '\n') 75 | opn(uri) 76 | }) 77 | 78 | // 错误处理 79 | app.on('error', (err) => { 80 | console.error('Server error: \n%s\n%s ', err.stack || '') 81 | }) 82 | 83 | const server = app.listen(appConfig.appPort) 84 | 85 | process.on('SIGTERM', () => { 86 | console.log('Stopping dev server') 87 | devMiddleware.close() 88 | server.close(() => { 89 | process.exit(0) 90 | }) 91 | }) -------------------------------------------------------------------------------- /webpack4-ssr-config/client/components/ProgressBar.vue: -------------------------------------------------------------------------------- 1 | 9 | 86 | 87 | 100 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/vue.koa.ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vue koa2 ssr中间件 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const fs = require('fs') 6 | const path = require('path') 7 | const LRU = require('lru-cache') 8 | const { createBundleRenderer } = require('vue-server-renderer') 9 | const isProd = process.env.NODE_ENV === 'production' 10 | const proxyConfig = require('./../app.config').proxy 11 | const setUpDevServer = require('./setup.dev.server') 12 | 13 | module.exports = function (app, uri) { 14 | 15 | const renderData = (ctx, renderer) => { 16 | const context = { 17 | url: ctx.url, 18 | title: 'Vue Koa2 SSR', 19 | cookies: ctx.request.headers.cookie 20 | } 21 | return new Promise((resolve, reject) => { 22 | renderer.renderToString(context, (err, html) => { 23 | if (err) { 24 | return reject(err) 25 | } 26 | resolve(html) 27 | }) 28 | }) 29 | } 30 | 31 | function createRenderer(bundle, options) { 32 | return createBundleRenderer(bundle, Object.assign(options, { 33 | cache: LRU({ 34 | max: 1000, 35 | maxAge: 1000 * 60 * 15 36 | }), 37 | runInNewContext: false 38 | })) 39 | } 40 | 41 | function resolve(dir) { 42 | return path.resolve(process.cwd(), dir) 43 | } 44 | 45 | let renderer 46 | if (isProd) { 47 | // prod mode 48 | const template = fs.readFileSync(resolve('dist/index.html'), 'utf-8') 49 | const bundle = require(resolve('dist/vue-ssr-server-bundle.json')) 50 | const clientManifest = require(resolve('dist/vue-ssr-client-manifest.json')) 51 | renderer = createRenderer(bundle, { 52 | template, 53 | clientManifest 54 | }) 55 | } else { 56 | // dev mode 57 | setUpDevServer(app, uri, (bundle, options) => { 58 | try { 59 | renderer = createRenderer(bundle, options) 60 | } catch (e) { 61 | console.log('\nbundle error', e) 62 | } 63 | } 64 | ) 65 | } 66 | app.use(async (ctx, next) => { 67 | if (!renderer) { 68 | ctx.type = 'html' 69 | return ctx.body = 'waiting for compilation... refresh in a moment.'; 70 | } 71 | if (Object.keys(proxyConfig).findIndex(vl => ctx.url.startsWith(vl)) > -1) { 72 | return next() 73 | } 74 | let html, status 75 | try { 76 | status = 200 77 | html = await renderData(ctx, renderer) 78 | } catch (e) { 79 | console.log('\ne', e) 80 | if (e.code === 404) { 81 | status = 404 82 | html = '404 | Not Found' 83 | } else { 84 | status = 500 85 | html = '500 | Internal Server Error' 86 | } 87 | } 88 | ctx.type = 'html' 89 | ctx.status = status ? status : ctx.status 90 | ctx.body = html 91 | }) 92 | } -------------------------------------------------------------------------------- /react-base-webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ssr-webpack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "cross-env NODE_ENV=development node config/index.js", 8 | "build": "rimraf dist && cross-env NODE_ENV=production webpack --config config/webpack.config.prod.js --progress --hide-modules", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "zdliuccit", 12 | "license": "ISC", 13 | "keywords": [ 14 | "react", 15 | "vue-ssr", 16 | "ssr", 17 | "koa", 18 | "koa2", 19 | "webpack4" 20 | ], 21 | "dependencies": { 22 | "antd": "^3.10.4", 23 | "react": "^16.6.0", 24 | "react-dom": "^16.6.0", 25 | "react-router-dom": "^4.3.1", 26 | "redux": "^4.0.1" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "7.1.2", 30 | "@babel/plugin-proposal-class-properties": "^7.1.0", 31 | "@babel/polyfill": "7.0.0", 32 | "@babel/preset-env": "7.1.0", 33 | "@babel/preset-react": "^7.0.0", 34 | "autoprefixer": "9.1.5", 35 | "axios": "0.18.0", 36 | "babel-eslint": "10.0.1", 37 | "babel-loader": "8.0.4", 38 | "babel-plugin-import": "^1.11.0", 39 | "case-sensitive-paths-webpack-plugin": "2.1.2", 40 | "cross-env": "5.2.0", 41 | "css-loader": "^1.0.0", 42 | "cssnano": "4.1.4", 43 | "eslint": "5.6.1", 44 | "eslint-config-standard": "12.0.0", 45 | "eslint-friendly-formatter": "4.0.1", 46 | "eslint-loader": "2.1.1", 47 | "eslint-plugin-html": "4.0.6", 48 | "eslint-plugin-import": "2.14.0", 49 | "eslint-plugin-node": "7.0.1", 50 | "eslint-plugin-promise": "4.0.1", 51 | "eslint-plugin-standard": "4.0.0", 52 | "extract-css-chunks-webpack-plugin": "3.1.1", 53 | "file-loader": "2.0.0", 54 | "friendly-errors-webpack-plugin": "1.7.0", 55 | "html-webpack-plugin": "3.2.0", 56 | "ip": "1.1.5", 57 | "json-loader": "0.5.7", 58 | "koa": "2.5.3", 59 | "koa-better-http-proxy": "0.2.4", 60 | "koa-compress": "2.0.0", 61 | "koa-convert": "1.2.0", 62 | "koa-logger": "3.2.0", 63 | "koa-router": "7.4.0", 64 | "koa-static": "5.0.0", 65 | "koa-webpack-dev-middleware": "2.0.2", 66 | "koa-webpack-hot-middleware": "1.0.3", 67 | "lru-cache": "4.1.3", 68 | "memory-fs": "0.4.1", 69 | "node-sass": "^4.9.4", 70 | "opn": "5.4.0", 71 | "optimize-css-assets-webpack-plugin": "5.0.1", 72 | "postcss": "7.0.4", 73 | "postcss-loader": "3.0.0", 74 | "postcss-pxtorem": "4.0.1", 75 | "sass-loader": "^7.1.0", 76 | "style-loader": "^0.23.1", 77 | "url-loader": "1.1.1", 78 | "webpack": "4.24.0", 79 | "webpack-cli": "3.1.2", 80 | "webpack-dev-middleware": "3.4.0", 81 | "webpack-hot-middleware": "2.24.2", 82 | "webpack-merge": "4.1.4" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /react-base-webpack/config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack prod配置 3 | * Created by zdliuccit on 2018/11/1. 4 | */ 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const base = require('./webpack.config.base')() 8 | const appWebpack = require('./../app.config').webpack 9 | const ExtractCssChunks = require("extract-css-chunks-webpack-plugin") 10 | const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') 11 | 12 | const config = merge(base, { 13 | mode: 'production', 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.css$/, 18 | use: [ExtractCssChunks.loader, 'css-loader', 'postcss-loader'], 19 | }, 20 | { 21 | test: /\.scss$/, 22 | use: [ExtractCssChunks.loader, 'css-loader', 'postcss-loader', 'sass-loader'], 23 | }, 24 | ] 25 | }, 26 | plugins: [ 27 | // 分离css文件 28 | new ExtractCssChunks({ 29 | filename: 'css/[name].[chunkhash:8].css', 30 | chunkFilename: 'css/[id].[chunkhash:8].css', 31 | }), 32 | // 限制文件最小KB 33 | new webpack.optimize.MinChunkSizePlugin({ 34 | minChunkSize: 20000 35 | }), 36 | new OptimizeCssAssetsPlugin( 37 | { 38 | cssProcessor: require('cssnano'), 39 | cssProcessorOptions: { 40 | // postcss那边已经处理过autoprefixer了,这里把它关掉,否则会导致浏览器前缀兼容范围问题 41 | autoprefixer: false, 42 | discardComments: { removeAll: true } 43 | }, 44 | } 45 | ), 46 | ], 47 | // production模式下,将侧重于模块体积优化和线上部署,包含如下内容: 48 | // 开启所有的优化代码 49 | // 更小的bundle大小 50 | // 去除掉只在开发阶段运行的代码 51 | // Scope hoisting和Tree-shaking 52 | // 自动启用uglifyjs对代码进行压缩 53 | optimization: { 54 | minimize: true, //取代 new UglifyJsPlugin(/* ... */) 55 | providedExports: true, 56 | usedExports: true, 57 | //识别package.json中的sideEffects以剔除无用的模块,用来做tree-shake 58 | //依赖于optimization.providedExports和optimization.usedExports 59 | sideEffects: true, 60 | //取代 new webpack.optimize.ModuleConcatenationPlugin() 61 | concatenateModules: true, 62 | //取代 new webpack.NoEmitOnErrorsPlugin(),编译错误时不打印输出资源。 63 | noEmitOnErrors: true 64 | }, 65 | optimization: { 66 | minimize: env === 'production' ? true : false, //是否进行代码压缩 67 | splitChunks: { 68 | chunks: "async", 69 | minSize: 30000, //模块大于30k会被抽离到公共模块 70 | minChunks: 1, //模块出现1次就会被抽离到公共模块 71 | maxAsyncRequests: 5, //异步模块,一次最多只能被加载5个 72 | maxInitialRequests: 3, //入口模块最多只能加载3个 73 | name: true, 74 | cacheGroups: { 75 | default: { 76 | minChunks: 2, 77 | priority: -20 78 | reuseExistingChunk: true, 79 | }, 80 | vendors: { 81 | test: /[\\/]node_modules[\\/]/, 82 | priority: -10 83 | } 84 | } 85 | }, 86 | runtimeChunk: { 87 | name: 'runtime' 88 | } 89 | } 90 | }, appWebpack) 91 | 92 | module.exports = config 93 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/setup.dev.server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * koa2 webpack4 开发服务 3 | * Created by zdliuccit on 2018/7/6. 4 | */ 5 | const path = require('path') 6 | const MFS = require('memory-fs') 7 | const webpack = require('webpack') 8 | const clientConfig = require('./webpack.client.config') 9 | const serverConfig = require('./webpack.server.config') 10 | const webpackDevMiddleware = require('koa-webpack-dev-middleware') 11 | const webpackHotMiddleware = require('koa-webpack-hot-middleware') 12 | const convert = require('koa-convert') 13 | 14 | const opn = require('opn') 15 | const readFile = (fs, file) => fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8') 16 | 17 | module.exports = function setupDevServer(app, uri, cb) { 18 | let bundle 19 | let template 20 | 21 | const update = () => { 22 | if (bundle && template) { 23 | cb(bundle, { 24 | template, 25 | }) 26 | } 27 | } 28 | 29 | // client 30 | clientConfig.entry.app = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true', clientConfig.entry.app] 31 | clientConfig.output.filename = '[name].js' 32 | clientConfig.plugins.push( 33 | new webpack.HotModuleReplacementPlugin(), 34 | new webpack.NoEmitOnErrorsPlugin() 35 | ) 36 | 37 | // webpack config 38 | const clientCompiler = webpack(clientConfig) 39 | 40 | // dev middleware 41 | const devMiddleware = webpackDevMiddleware(clientCompiler, { 42 | publicPath: clientConfig.output.publicPath, 43 | noInfo: true, 44 | headers: { 'Access-Control-Allow-Origin': '*' }, 45 | stats: { 46 | colors: true, 47 | modules: false, 48 | }, 49 | }) 50 | 51 | app.use(convert(devMiddleware)) 52 | 53 | // hot update 54 | clientCompiler.plugin('done', stats => { 55 | const fs = devMiddleware.fileSystem 56 | stats = stats.toJson() 57 | stats.errors.forEach(err => console.error(err)) 58 | stats.warnings.forEach(err => console.warn(err)) 59 | if (stats.errors.length) return 60 | 61 | console.log('\nclient-dev...\n') 62 | 63 | let filePath = path.join(clientConfig.output.path, 'index.html') 64 | if (fs.existsSync(filePath)) { 65 | // 读取内存模板 66 | template = readFile(fs, 'index.html') 67 | } 68 | update() 69 | }) 70 | 71 | // hot middleware 72 | app.use(convert(webpackHotMiddleware(clientCompiler))) 73 | 74 | // server 75 | const serverCompiler = webpack(serverConfig) 76 | const mfs = new MFS() 77 | serverCompiler.outputFileSystem = mfs 78 | serverCompiler.watch({}, (err, stats) => { 79 | if (err) throw err 80 | stats = stats.toJson() 81 | if (stats.errors.length) return 82 | 83 | console.log('server-dev...') 84 | bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json')) 85 | update() 86 | }) 87 | 88 | devMiddleware.waitUntilValid(() => { 89 | console.log('\n> Listening at ' + uri + '\n') 90 | opn(uri) 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /webpack3-basic-config/config/eslintrc.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * eslint规则配置,用于被业务工程引用 3 | */ 4 | module.exports = { 5 | root: true, 6 | env: { 7 | // 环境定义了预定义的全局变量。 8 | browser: true, 9 | node: true, 10 | es6: true, 11 | mocha: true 12 | }, 13 | parser: 'babel-eslint', //使用babel-eslint来作为eslint的解析器 14 | parserOptions: { 15 | // ECMAScript 版本 16 | ecmaVersion: 6, 17 | sourceType: 'module', 18 | // // 想使用的额外的语言特性: 19 | ecmaFeatures: { 20 | experimentalObjectRestSpread: true, 21 | } 22 | }, 23 | extends: 'standard', 24 | plugins: [ 25 | 'html', 26 | 'import', 27 | 'promise', 28 | ], 29 | // add your custom rules here 30 | rules: { 31 | // 禁止条件表达式中出现赋值操作符 32 | 'no-cond-assign': 2, 33 | // 允许console语句 34 | 'no-console': 1, 35 | // 允许 debugger 36 | 'no-debugger': 0, 37 | // 禁止 function 定义中出现重名参数 38 | 'no-dupe-args': 2, 39 | // var声明 40 | 'no-var': 1, 41 | // 分号; 42 | 'semi': [ 43 | 0, 44 | 'always' 45 | ], 46 | // 使用 === 替代 == allow-null允许null和undefined== 47 | 'eqeqeq': [ 48 | 2, 49 | 'allow-null' 50 | ], 51 | // 禁用 alert、confirm 和 prompt 52 | 'no-alert': 2, 53 | // 禁用 eval() 54 | 'no-eval': 2, 55 | // 禁用 with 语句 56 | 'no-with': 2, 57 | // 要求或禁止使用严格模式指令 58 | 'strict': 2, 59 | ////////////// 60 | // 要求或禁止 var 声明中的初始化(初值) 61 | 'init-declarations': 2, 62 | // 不允许 catch 子句的参数与外层作用域中的变量同名 63 | 'no-catch-shadow': 0, 64 | // 禁止删除变量 65 | 'no-delete-var': 2, 66 | // 不允许标签与变量同名 67 | 'no-label-var': 2, 68 | // 禁用特定的全局变量 69 | 'no-restricted-globals': 0, 70 | // 禁止 var 声明 与外层作用域的变量同名 71 | 'no-shadow': 0, 72 | // 禁止覆盖受限制的标识符 73 | 'no-shadow-restricted-names': 2, 74 | // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到 75 | 'no-undef': 2, 76 | // 禁止将变量初始化为 undefined 77 | 'no-undef-init': 2, 78 | // 禁止将 undefined 作为标识符 79 | 'no-undefined': 0, 80 | // 禁止出现未使用过的变量 81 | 'no-unused-vars': [ 82 | 0, 83 | { 84 | 'vars': 'all', 85 | 'args': 'none' 86 | } 87 | ], 88 | // 不允许在变量定义之前使用它们 89 | 'no-use-before-define': 0, 90 | // 强制一行的最大长度 91 | 'max-len': [ 92 | 1, 93 | 200 94 | ], 95 | // 文件末尾强制换行 96 | 'eol-last': 0, 97 | // 强制使用一致的反勾号、双引号或单引号 98 | 'quotes': [ 99 | 2, 100 | 'single' 101 | ], 102 | // 禁止修改 const 声明的变量 103 | 'no-const-assign': 2, 104 | // 禁止标识符中有悬空下划线_bar 105 | 'no-underscore-dangle': 0, 106 | // 禁用行尾空格 107 | 'no-trailing-spaces': 2, 108 | // 禁用不必要的嵌套块 109 | 'no-lone-blocks': 2, 110 | // 强制在 JSX 属性中一致地使用双引号或单引号 111 | 'jsx-quotes': 0, 112 | // 函数定义时括号前面要不要有空格 这里忽略 113 | 'space-before-function-paren': [0, `always`], 114 | //对象字面量项尾不能有逗号 这里忽略 115 | 'comma-dangle': [0, 'always'], 116 | }, 117 | } 118 | -------------------------------------------------------------------------------- /react-base-webpack/config/eslintrc.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * eslint规则配置,用于被业务工程引用 3 | * Created by zdliuccit on 2018/11/1. 4 | */ 5 | 6 | module.exports = { 7 | root: true, 8 | env: { 9 | // 环境定义了预定义的全局变量。 10 | browser: true, 11 | node: true, 12 | es6: true, 13 | mocha: true 14 | }, 15 | parser: 'babel-eslint', 16 | parserOptions: { 17 | // ECMAScript 版本 18 | ecmaVersion: 6, 19 | sourceType: 'module', 20 | }, 21 | extends: 'standard', 22 | plugins: [ 23 | 'html', 24 | 'import', 25 | 'promise', 26 | ], 27 | // add your custom rules here 0忽略 1warn 2 error 28 | rules: { 29 | // 缩进4空格 禁用2 30 | 'indent': [1, 2], 31 | // 禁止条件表达式中出现赋值操作符 32 | 'no-cond-assign': 2, 33 | // 允许console语句 34 | 'no-console': 1, 35 | // 允许 debugger 36 | 'no-debugger': 1, 37 | // var声明 38 | 'no-var': 2, 39 | // 禁止 function 定义中出现重名参数 40 | 'no-dupe-args': 2, 41 | // 禁止重复的函数声明 42 | 'no-func-assign': 2, 43 | // 忽略分号; 44 | 'semi': [1, 'never'], 45 | // 使用 === 和 !== 46 | 'eqeqeq': [2, 'allow-null'], 47 | // warn alert、 48 | 'no-alert': 1, 49 | // 禁用 eval() 50 | 'no-eval': 2, 51 | // 禁用 with 语句 52 | 'no-with': 2, 53 | // 要求或禁止使用严格模式指令 54 | 'strict': 2, 55 | // 要求或禁止 var 声明中的初始化(初值) 56 | 'init-declarations': 2, 57 | // 不允许 catch 子句的参数与外层作用域中的变量同名 58 | 'no-catch-shadow': 0, 59 | // 禁止删除变量 60 | 'no-delete-var': 2, 61 | // 不允许标签与变量同名 62 | 'no-label-var': 2, 63 | // 禁用特定的全局变量 64 | 'no-restricted-globals': 2, 65 | // 禁止 var 声明 与外层作用域的变量同名 66 | 'no-shadow': 0, 67 | // 禁止覆盖受限制的标识符 68 | 'no-shadow-restricted-names': 2, 69 | // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到 70 | 'no-undef': 2, 71 | // 禁止将变量初始化为 undefined 72 | 'no-undef-init': 2, 73 | // 禁止将 undefined 作为标识符 74 | 'no-undefined': 2, 75 | // 禁止出现未使用过的变量 76 | 'no-unused-vars': [1, { 'vars': 'all', 'args': 'none' }], 77 | // 不允许在变量定义之前使用它们 78 | 'no-use-before-define': 1, 79 | // 强制一行的最大长度 80 | 'max-len': [1, 160], 81 | // 文件末尾强制换行 82 | 'eol-last': 0, 83 | // 强制使用单引号 84 | 'quotes': [2, 'single'], 85 | // 禁止修改 const 声明的变量 86 | 'no-const-assign': 2, 87 | // 禁止标识符中有悬空下划线_bar,这里忽略 88 | 'no-underscore-dangle': 0, 89 | // 禁用行尾空格 90 | 'no-trailing-spaces': 2, 91 | // 禁用不必要的嵌套块 92 | 'no-lone-blocks': 2, 93 | // 强制在 JSX 属性中一致地使用双引号或单引号 94 | 'jsx-quotes': 0, 95 | // 函数定义时括号前面要不要有空格 96 | 'space-before-function-paren': [1, `never`], 97 | //对象字面量项尾不能有逗号 这里忽略 98 | 'comma-dangle': [0, 'always'], 99 | // 在对象字面量属性中实现键和值之间的一致间隔 {key: value} 100 | 'key-spacing': [1, { 'mode': 'strict' }], 101 | // 允许对象所有键和值在同一行上 102 | 'object-property-newline': [0, { 'allowMultiplePropertiesPerLine': true }], 103 | // promise reject 参数设置为 * 任意类型 104 | 'prefer-promise-reject-errors': [0, { 'allowEmptyReject': true }] 105 | }, 106 | } 107 | -------------------------------------------------------------------------------- /webpack4-basic-config/src/utils/storage/README.md: -------------------------------------------------------------------------------- 1 | # x-vuex-storage 2 | 3 | 基于 vuex 的数据存储栈 4 | 5 | ## GET STARTED 6 | 7 | 安装所依赖的包 8 | ```bash 9 | npm i 10 | ``` 11 | 12 | 启动服务用于查看 demo 13 | ```bash 14 | npm start 15 | ``` 16 | 17 | ## USAGE 18 | 19 | 在最开始的时候请用以下方式实例化此方法 20 | ```javascript 21 | import vueStorage from './utils/storage' 22 | import Vue from 'vue' 23 | import VueRouter from 'vue-router' 24 | 25 | const router = new VueRouter(...) 26 | 27 | /** 28 | * @param {Object} Vue Vue 29 | * @param {router} [router=undefined] VueRouter 实例化对象 30 | * @param {array} [whiteList=[]] 路由白名单 31 | * @param {Function} cb 回调函数 函数内返回 Promise 32 | * 函数的返回参数有: 33 | * $storage -- VuexStorage 的对象 34 | * to -- router beforeEach 的 to 35 | * from -- router beforeEach 的 from 36 | */ 37 | const store = VuexStorage(Vue, router, whiteList, ($storage, to, from) => Promise.resolve()) 38 | 39 | new Vue({ 40 | el: '#app', 41 | router, 42 | store, 43 | render: h => h(App) 44 | }) 45 | ``` 46 | 47 | 暴露在原型链上的对象为 48 | ```javascript 49 | this.$storage 50 | ``` 51 | 52 | 此对象的属性为 53 | ```javascript 54 | // 为路由白名单,传入一个数组 55 | this.$storage.whiteList 56 | ``` 57 | 58 | # :warning:警告 59 | ### 每一个方法中注意 isTemp 这个参数 60 | ### 默认为 true 用于存放至临时仓库会在每次路由变更且不为白名单的路径时清空此仓库 61 | ### 如果将手动变为 false 将会存放至永久仓库,只会在页面物理刷新和新开页面时清空 62 | 63 | 此对象的方法分别为 64 | 65 | ```javascript 66 | /** 67 | * 存储一项到仓库 68 | * @method setItem 69 | * @param {string|Array} key 需要存储的键 70 | * @param {any} value 需要存储的值 71 | * @param {boolean} [isTemp=true] 是否存储到临时的仓库 72 | */ 73 | this.$storage.setItem(key, value, isTemp) 74 | 75 | /** 76 | * 用于快速增加 item 列表和更新白名单 77 | * 此方法在使用时会自动将对象和数组自动赋值给· items 的 value 78 | * 但是用值类型的变量需要在手动使用 getItem 获取 79 | * @method hyperChannel 80 | * @param {Array} [whiteList=[]] 路由白名单 81 | * @param {boolean} [isTemp=true] 是否存储到临时的仓库,默认为 true 82 | * @param {RestObejct} items rest 风格 item 列表 83 | */ 84 | this.$storage.hyperChannel(whiteList = [], isTemp = true, ...items) 85 | 86 | /** 87 | * 删除指定的一项 88 | * @method removeItem 89 | * @param {string|Array} key 仓库中的键 90 | * @param {boolean} [isTemp=true] 是否删除临时的仓库 91 | */ 92 | this.$storage.removeItem(key, isTemp) 93 | 94 | /** 95 | * 重置指定项 96 | * @method resetItem 97 | * @param {string|Array} key 仓库中的键 98 | * @param {boolean} [isTemp=true] 是否删除临时的仓库 99 | */ 100 | this.$storage.resetItem(key, isTemp) 101 | 102 | /** 103 | * 清除所有 104 | * @method clear 105 | * @param {boolean} [isTemp=true] 是否清楚临时的仓库 106 | */ 107 | this.$storage.clear(isTemp) 108 | /** 109 | * 更新指定项 110 | * @method updateItem 111 | * @param {string|Array} key 仓库中的键 112 | * @param {any} value 需要修改的值 113 | * @param {boolean} [isTemp=true] 是否存储到临时的仓库 114 | */ 115 | this.$storage.updateItem(key, value, isTemp) 116 | 117 | /** 118 | * 获取仓库中的指定值 119 | * @method getItem 120 | * @param {string|Array} key 仓库中的键 121 | * @param {boolean} [isTemp=true] 是否存储到临时的仓库 122 | * @return {any} 仓库中存储的值 123 | */ 124 | this.$storage.getItem(key, isTemp) 125 | ``` -------------------------------------------------------------------------------- /webpack4-ssr-config/config/eslintrc.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * eslint规则配置,用于被业务工程引用 3 | * Created by liuzhengdong on 2018/4/3. 4 | */ 5 | 6 | module.exports = { 7 | root: true, 8 | env: { 9 | // 环境定义了预定义的全局变量。 10 | browser: true, 11 | node: true, 12 | es6: true, 13 | mocha: true 14 | }, 15 | parser: 'babel-eslint', 16 | parserOptions: { 17 | // ECMAScript 版本 18 | ecmaVersion: 6, 19 | sourceType: 'module', 20 | }, 21 | extends: 'standard', 22 | plugins: [ 23 | 'html', 24 | 'import', 25 | 'promise', 26 | ], 27 | // add your custom rules here 0忽略 1warn 2 error 28 | rules: { 29 | // 缩进4空格 禁用2 忽悠注释部分 30 | 'indent': [1, 2, { "ignoreComments": true }], 31 | // 禁止条件表达式中出现赋值操作符 32 | 'no-cond-assign': 2, 33 | // 允许console语句 34 | 'no-console': 1, 35 | // 允许 debugger 36 | 'no-debugger': 1, 37 | // var声明 38 | 'no-var': 2, 39 | // 禁止 function 定义中出现重名参数 40 | 'no-dupe-args': 2, 41 | // 禁止重复的函数声明 42 | 'no-func-assign': 2, 43 | // 忽略分号; 44 | 'semi': [1, 'never'], 45 | // 使用 === 和 !== 46 | 'eqeqeq': [2, 'allow-null'], 47 | // warn alert、 48 | 'no-alert': 1, 49 | // 禁用 eval() 50 | 'no-eval': 2, 51 | // 禁用 with 语句 52 | 'no-with': 2, 53 | // 要求或禁止使用严格模式指令 54 | 'strict': 2, 55 | // 要求或禁止 var 声明中的初始化(初值) 56 | 'init-declarations': 2, 57 | // 不允许 catch 子句的参数与外层作用域中的变量同名 58 | 'no-catch-shadow': 0, 59 | // 禁止删除变量 60 | 'no-delete-var': 2, 61 | // 不允许标签与变量同名 62 | 'no-label-var': 2, 63 | // 禁用特定的全局变量 64 | 'no-restricted-globals': 2, 65 | // 禁止 var 声明 与外层作用域的变量同名 66 | 'no-shadow': 0, 67 | // 禁止覆盖受限制的标识符 68 | 'no-shadow-restricted-names': 2, 69 | // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到 70 | 'no-undef': 2, 71 | // 禁止将变量初始化为 undefined 72 | 'no-undef-init': 2, 73 | // 禁止将 undefined 作为标识符 74 | 'no-undefined': 2, 75 | // 禁止出现未使用过的变量 76 | 'no-unused-vars': [1, { 'vars': 'all', 'args': 'none' }], 77 | // 不允许在变量定义之前使用它们 78 | 'no-use-before-define': 1, 79 | // 强制一行的最大长度 80 | 'max-len': [1, 160], 81 | // 文件末尾强制换行 82 | 'eol-last': 0, 83 | // 强制使用单引号 84 | 'quotes': [2, 'single'], 85 | // 禁止修改 const 声明的变量 86 | 'no-const-assign': 2, 87 | // 禁止标识符中有悬空下划线_bar,这里忽略 88 | 'no-underscore-dangle': 0, 89 | // 禁用行尾空格 90 | 'no-trailing-spaces': 2, 91 | // 禁用不必要的嵌套块 92 | 'no-lone-blocks': 2, 93 | // 强制在 JSX 属性中一致地使用双引号或单引号 94 | 'jsx-quotes': 0, 95 | // 函数定义时括号前面要不要有空格 96 | 'space-before-function-paren': [1, `never`], 97 | //对象字面量项尾不能有逗号 这里忽略 98 | 'comma-dangle': [0, 'always'], 99 | // 在对象字面量属性中实现键和值之间的一致间隔 {key: value} 100 | 'key-spacing': [1, { 'mode': 'strict' }], 101 | // 允许对象所有键和值在同一行上 102 | 'object-property-newline': [0, { 'allowMultiplePropertiesPerLine': true }], 103 | // promise reject 参数设置为 * 任意类型 104 | 'prefer-promise-reject-errors': [0, { 'allowEmptyReject': true }] 105 | }, 106 | } 107 | -------------------------------------------------------------------------------- /webpack4-basic-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack4-basic-config", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "rimraf dist && npm run dll && cross-env NODE_ENV=development node config/index.js", 8 | "build": "rimraf dist && npm run dll && npm run prod", 9 | "dll": "webpack --progress --hide-modules --config config/webpack.config.dll.js", 10 | "prod": "cross-env NODE_ENV=production webpack --config config/webpack.config.prod.js --progress --hide-modules", 11 | "fix": "eslint src --ext .js,.vue --fix", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": [ 15 | "Vue", 16 | "Webpack", 17 | "Koa2", 18 | "Koa" 19 | ], 20 | "author": "zdliuccit", 21 | "license": "ISC", 22 | "dependencies": { 23 | "vue": "2.5.20", 24 | "vue-router": "3.0.2", 25 | "vuex": "3.0.1" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "7.2.0", 29 | "@babel/plugin-syntax-dynamic-import": "7.2.0", 30 | "@babel/plugin-syntax-jsx": "7.2.0", 31 | "@babel/polyfill": "7.0.0", 32 | "@babel/preset-env": "7.2.0", 33 | "autoprefixer": "9.4.2", 34 | "axios": "0.18.0", 35 | "babel-eslint": "10.0.1", 36 | "babel-helper-vue-jsx-merge-props": "2.0.3", 37 | "babel-loader": "8.0.4", 38 | "babel-plugin-transform-vue-jsx": "4.0.1", 39 | "case-sensitive-paths-webpack-plugin": "2.1.2", 40 | "cross-env": "5.2.0", 41 | "css-loader": "1.0.0", 42 | "cssnano": "4.1.4", 43 | "element-ui": "^2.4.11", 44 | "eslint": "5.6.1", 45 | "eslint-config-standard": "12.0.0", 46 | "eslint-friendly-formatter": "4.0.1", 47 | "eslint-loader": "2.1.1", 48 | "eslint-plugin-html": "4.0.6", 49 | "eslint-plugin-import": "2.14.0", 50 | "eslint-plugin-node": "7.0.1", 51 | "eslint-plugin-promise": "4.0.1", 52 | "eslint-plugin-standard": "4.0.0", 53 | "extract-css-chunks-webpack-plugin": "3.2.1", 54 | "file-loader": "2.0.0", 55 | "friendly-errors-webpack-plugin": "1.7.0", 56 | "html-webpack-plugin": "3.2.0", 57 | "ip": "1.1.5", 58 | "json-loader": "0.5.7", 59 | "koa": "2.6.2", 60 | "koa-better-http-proxy": "0.2.4", 61 | "koa-compress": "2.0.0", 62 | "koa-convert": "1.2.0", 63 | "koa-logger": "3.2.0", 64 | "koa-router": "7.4.0", 65 | "koa-static": "5.0.0", 66 | "koa-webpack-dev-middleware": "2.0.2", 67 | "koa-webpack-hot-middleware": "1.0.3", 68 | "opn": "5.4.0", 69 | "optimize-css-assets-webpack-plugin": "5.0.1", 70 | "postcss": "7.0.6", 71 | "postcss-loader": "3.0.0", 72 | "postcss-pxtorem": "4.0.1", 73 | "progressbar.js": "^1.0.1", 74 | "stylus": "0.54.5", 75 | "stylus-loader": "3.0.2", 76 | "url-loader": "1.1.2", 77 | "vue-loader": "15.4.2", 78 | "vue-style-loader": "4.1.2", 79 | "vue-template-compiler": "2.5.20", 80 | "webpack": "4.27.1", 81 | "webpack-cli": "3.1.2", 82 | "webpack-dev-middleware": "3.4.0", 83 | "webpack-hot-middleware": "2.24.3", 84 | "webpack-merge": "4.1.5", 85 | "winston": "2.3.1" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/eslintrc.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * eslint规则配置,用于被业务工程引用 3 | * Created by liuzhengdong on 2018/4/3. 4 | */ 5 | 6 | module.exports = { 7 | root: true, 8 | env: { 9 | // 环境定义了预定义的全局变量。 10 | browser: true, 11 | node: true, 12 | es6: true, 13 | mocha: true 14 | }, 15 | parser: 'babel-eslint', 16 | parserOptions: { 17 | // ECMAScript 版本 18 | ecmaVersion: 6, 19 | sourceType: 'module', 20 | }, 21 | extends: 'standard', 22 | plugins: [ 23 | 'html', 24 | 'import', 25 | 'promise', 26 | ], 27 | // add your custom rules here 0忽略 1warn 2 error 28 | rules: { 29 | // 缩进4空格 禁用2 忽悠注释部分 30 | 'indent': [1, 2, {'ignoreComments': true}], 31 | // 禁止条件表达式中出现赋值操作符 32 | 'no-cond-assign': 2, 33 | // 允许console语句 34 | 'no-console': 1, 35 | // 允许 debugger 36 | 'no-debugger': 1, 37 | // var声明 38 | 'no-var': 2, 39 | // 禁止 function 定义中出现重名参数 40 | 'no-dupe-args': 2, 41 | // 禁止重复的函数声明 42 | 'no-func-assign': 2, 43 | // 忽略分号; 44 | 'semi': [1, 'never'], 45 | // 使用 === 和 !== 46 | 'eqeqeq': [2, 'allow-null'], 47 | // warn alert、 48 | 'no-alert': 1, 49 | // 禁用 eval() 50 | 'no-eval': 2, 51 | // 禁用 with 语句 52 | 'no-with': 2, 53 | // 要求或禁止使用严格模式指令 54 | 'strict': 2, 55 | // 要求或禁止 var 声明中的初始化(初值) 56 | 'init-declarations': 2, 57 | // 不允许 catch 子句的参数与外层作用域中的变量同名 58 | 'no-catch-shadow': 0, 59 | // 禁止删除变量 60 | 'no-delete-var': 2, 61 | // 不允许标签与变量同名 62 | 'no-label-var': 2, 63 | // 禁用特定的全局变量 64 | 'no-restricted-globals': 2, 65 | // 禁止 var 声明 与外层作用域的变量同名 66 | 'no-shadow': 0, 67 | // 禁止覆盖受限制的标识符 68 | 'no-shadow-restricted-names': 2, 69 | // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到 70 | 'no-undef': 2, 71 | // 禁止将变量初始化为 undefined 72 | 'no-undef-init': 2, 73 | // 禁止将 undefined 作为标识符 74 | 'no-undefined': 2, 75 | // 禁止出现未使用过的变量 76 | 'no-unused-vars': [1, {'vars': 'all', 'args': 'none'}], 77 | // 不允许在变量定义之前使用它们 78 | 'no-use-before-define': 1, 79 | // 强制一行的最大长度 80 | 'max-len': [1, 160], 81 | // 文件末尾强制换行 82 | 'eol-last': 0, 83 | // 强制使用单引号 84 | 'quotes': [2, 'single'], 85 | // 禁止修改 const 声明的变量 86 | 'no-const-assign': 2, 87 | // 禁止标识符中有悬空下划线_bar,这里忽略 88 | 'no-underscore-dangle': 0, 89 | // 禁用行尾空格 90 | 'no-trailing-spaces': 2, 91 | // 禁用不必要的嵌套块 92 | 'no-lone-blocks': 2, 93 | // 强制在 JSX 属性中一致地使用双引号或单引号 94 | 'jsx-quotes': 0, 95 | // 函数定义时括号前面要不要有空格 96 | 'space-before-function-paren': [1, `never`], 97 | //对象字面量项尾不能有逗号 这里忽略 98 | 'comma-dangle': [0, 'always'], 99 | // 在对象字面量属性中实现键和值之间的一致间隔 {key: value} 100 | 'key-spacing': [1, {'mode': 'strict'}], 101 | // 允许对象所有键和值在同一行上 102 | 'object-property-newline': [0, {'allowMultiplePropertiesPerLine': true}], 103 | // promise reject 参数设置为 * 任意类型 104 | 'prefer-promise-reject-errors': [0, {'allowEmptyReject': true}], 105 | 'object-curly-spacing': ['error', 'never', {'objectsInObjects': true}] 106 | }, 107 | } 108 | -------------------------------------------------------------------------------- /webpack4-ssr-config/config/middle/proxyMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * http代理中间件 匹配代理、请求重定向 3 | * 获取app.config.js配置文件,匹配proxy 4 | */ 5 | const urlUtils = require('url') 6 | const koaHttpProxy = require('koa-better-http-proxy') 7 | const compose = require('koa-compose') 8 | const appConfig = require('./../../app.config') 9 | const logger = require('./../logger/koa-logger')('proxyMiddleWare') 10 | 11 | const isProd = process.env.NODE_ENV === 'production' 12 | 13 | /** 14 | * 代理处理中间件 15 | * @return {Function} koa middleware 16 | */ 17 | module.exports = function () { 18 | async function preProxyMiddleware(ctx, next) { 19 | const url = ctx.url 20 | // logger.info(`Request '${url}'`) 21 | let proxyTarget 22 | let proxyConfig = appConfig.proxy 23 | // 在appConfig.proxy中寻找匹配前缀的代理 24 | for (const [prefix, target] of Object.entries(proxyConfig)) { 25 | if (url.startsWith(prefix)) { 26 | // 匹配替换 27 | ctx.url = url.replace(prefix, '') 28 | proxyTarget = target 29 | ctx._proxyTarget = proxyTarget 30 | logger.info(`Match to proxy: '${prefix}' => '${proxyTarget}'`) 31 | break 32 | } 33 | } 34 | if (!proxyTarget) { 35 | logger.info('Proxy not found') 36 | return Promise.resolve() 37 | } 38 | logger.info(`Will be Agent to '${proxyTarget + ctx.url}'`) 39 | return next() 40 | } 41 | 42 | /** 43 | * 顺序执行async函数 44 | */ 45 | return compose([ 46 | preProxyMiddleware, 47 | koaHttpProxy( 48 | (ctx) => { 49 | return ctx._proxyTarget 50 | }, 51 | { 52 | // 不解析body,不限制body大小 53 | parseReqBody: false, 54 | /** 55 | * 发出代理请求前的回调,更改头文件 56 | * @param {Object} proxyReqOpts - 代理请求选项 57 | * @param {ctx} ctx - koa ctx 58 | * @return {Promise.<*>} * 59 | */ 60 | async proxyReqOptDecorator(proxyReqOpts, ctx) { 61 | const parsedTarget = urlUtils.parse(ctx._proxyTarget, true) 62 | proxyReqOpts.host = parsedTarget.hostname 63 | proxyReqOpts.port = parsedTarget.port 64 | proxyReqOpts.https = parsedTarget.protocol === 'https:' 65 | 66 | // 去掉Referer头,否则可能会造成CSRF问题,影响开发 67 | if (!isProd) { 68 | delete proxyReqOpts.headers.Referer 69 | delete proxyReqOpts.headers.Origin 70 | } 71 | // 计时开始 72 | ctx._proxyStartTime = Date.now() 73 | return proxyReqOpts 74 | }, 75 | /** 76 | * 代理请求被响应后的回调 77 | * @param {Response} proxyRes - 代理请求选项 78 | * @param {Object} proxyResData - 响应数据 79 | * @param {ctx} ctx - koa ctx 80 | * @return {Promise.<*>} * 81 | */ 82 | async userResDecorator(proxyRes, proxyResData, ctx) { 83 | // logger.info('ProxyRes headers:', '\n', JSON.stringify(ctx.response.headers, null, 2)) 84 | const location = `${ctx._proxyTarget}${ctx.url}` 85 | logger.info(`Proxy request '${location}' completed(${proxyRes.statusCode}), costing ${Date.now() - ctx._proxyStartTime}ms.`) 86 | return proxyResData 87 | }, 88 | }), 89 | ]) 90 | } 91 | -------------------------------------------------------------------------------- /webpack3-basic-config/doc/npm包说明.md: -------------------------------------------------------------------------------- 1 | NPM包说明 2 | 3 | * `koa` 4 | * `koa-static`和`koa-view` 用于设置koa的静态文件目录和模板渲染 5 | * `koa-webpack-dev-middleware`和`koa-webpack-hot-middleware` 开发和热加载模块 6 | * `koa-convert` 将generator转成 async await异步中间件 7 | * `koa-compose` koa2不需要再借助于co这种工具库了,所以有了koa-compose 8 | * `koa-better-http-proxy` Koa中间件代理请求到另一个主机并通过响应 9 | * `url` This module has utilities for URL resolution and parsing meant to have feature parity with node.js core url module. 10 | 11 | * vue 12 | * vue-router 13 | * autoprefixer // css兼容性,对不同的浏览器加上前缀 14 | * opn // 打开指定浏览器 15 | * axios 用于浏览器和node.js的基于Promise的HTTP客户端 16 | * ora 优雅的终端旋转器 17 | * cross-env 运行跨平台设置和使用环境变量的脚本 18 | * `Lodash`这是一个具有一致接口、模块化、高性能等特性的 JavaScript 工具库 19 | 20 | * `babel-core` 21 | --- 22 | 如果你需要以编程的方式来使用 Babel,可以使用 babel-core 这个包。 23 | babel-core 的作用是把 js 代码分析成 ast ,方便各个插件分析语法进行相应的处理。有些新语法在低版本 js 中是不存在的, 24 | 如箭头函数,rest 参数,函数默认值等,这种语言层面的不兼容只能通过将代码转为 ast,分析其语法后再转为低版本 js。首先安装 babel-core。 25 | 还可以通过babel-register和babel-node使用Babel,但由于这两种用法不适合生产环境故省略。 26 | 27 | * `babel-preset-es2015` 打包了 es6 的特性 28 | * `babel-preset-latest` 29 | latest是一个特殊的presets,包括了es2015,es2016,es2017的插件(目前为止,以后有es2018也会包括进去)。 30 | 即总是包含最新的编译插件。 31 | * `babel-preset-env` 32 | 上面提到的各种preset的问题就是: 它们都太”重”了, 即包含了过多在某些情况下不需要的功能. 比如, 33 | 现代的浏览器大多支持ES6的generator, 但是如果你使用babel-preset-es2015, 34 | 它会将generator函数编译为复杂的ES5代码, 这是没有必要的。但使用babel-preset-env, 我们可以声明环境, 然后该preset就会只编译包含我们所声明环境缺少的特性的代码,因此也是比较推荐的方式。 35 | ```json 36 | { 37 | "presets": ["env"] 38 | } 39 | 40 | ``` 41 | * `babel-preset-stage-0` 打包处于 strawman 阶段的语法 0、1、2、3总共4个阶段 42 | * `babel-polyfill` 代码填充,也可译作兼容性补丁, 文件顶部引入就行,import "babel-polyfill"; 43 | * `babel-plugin-transform-runtime` 和 `babel-runtime` 功能和`babel-polyfill`一样 44 | ```js 45 | // 你不介意污染全局变量 用 babel-polyfill 46 | // 写模块,为了避免污染使用者的环境 只能用 babel-runtime + babel-plugin-transform-runtime。 47 | ``` 48 | * `babel-loader` 49 | * `babel-eslint` 50 | 51 | 52 | * `extract-text-webpack-plugin` 抽离js中的css样式 53 | * `url-loader`、`file-loader`打包文件和图片 url-loader是对file-loader的上层封装,比如webpack中对图片的加载器配置 54 | ```js 55 | {test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} 56 | //一般限制小图片转 base64 可以用 url-loader,其他情况都用 file-loader。 57 | ``` 58 | * `json-loader` 59 | * `vue-loader` 60 | * `style-loader` 样式装载机 通过注入 -------------------------------------------------------------------------------- /webpack3-basic-config/config/utils/proxyMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * http代理中间件 匹配代理、请求重定向 3 | * 获取app.config.js配置文件,匹配proxy 4 | */ 5 | const path = require('path') 6 | const urlUtils = require('url') 7 | const koaHttpProxy = require('koa-better-http-proxy') 8 | const compose = require('koa-compose') 9 | const appConfig = require('./../../app.config') 10 | const { IS_DEBUG } = require('./env') 11 | const logger = require('./logger/koa-logger')('proxyMiddleWare') 12 | 13 | const needToken = !!appConfig.token 14 | let tokenManager 15 | if (needToken) { 16 | tokenManager = require('./token')(appConfig.token) 17 | } 18 | 19 | /** 20 | * 获取代理配置 21 | * @return {*} 代理配置 22 | */ 23 | function getProxyConfig () { 24 | // 开发模式每次重新读取 25 | if (!IS_DEBUG) { 26 | return appConfig.proxy 27 | } 28 | // 生产环境读取 29 | const serverConfig = require(path.join(process.cwd(), 'server.config.js')) 30 | return serverConfig.proxy 31 | } 32 | 33 | /** 34 | * 代理处理中间件 35 | * @return {Function} koa middleware 36 | */ 37 | module.exports = function () { 38 | async function preProxyMiddleware (ctx, next) { 39 | const url = ctx.url 40 | logger.info(`Request '${url}'`) 41 | let proxyTarget 42 | let proxyConfig = getProxyConfig() 43 | // 在appConfig.proxy中寻找匹配前缀的代理 44 | for (const [prefix, target] of Object.entries(proxyConfig)) { 45 | if (url.startsWith(prefix)) { 46 | // 匹配替换 47 | if (!IS_DEBUG) { 48 | ctx.url = url.replace(prefix, '') 49 | } 50 | proxyTarget = target 51 | ctx._proxyTarget = proxyTarget 52 | 53 | logger.info(`Match to proxy: '${prefix}' => '${proxyTarget}'`) 54 | break 55 | } 56 | } 57 | if (!proxyTarget) { 58 | logger.info('Proxy not found, skipped') 59 | return Promise.resolve() 60 | } 61 | logger.info(`Will be Agent to '${proxyTarget + ctx.url}'`) 62 | return next() 63 | } 64 | 65 | /** 66 | * 顺序执行async函数 67 | */ 68 | return compose([ 69 | preProxyMiddleware, 70 | koaHttpProxy( 71 | (ctx) => { 72 | return ctx._proxyTarget 73 | }, 74 | { 75 | // 不解析body,不限制body大小 76 | parseReqBody: false, 77 | /** 78 | * 发出代理请求前的回调,更改头文件 79 | * @param {Object} proxyReqOpts - 代理请求选项 80 | * @param {ctx} ctx - koa ctx 81 | * @return {Promise.<*>} * 82 | */ 83 | async proxyReqOptDecorator (proxyReqOpts, ctx) { 84 | const parsedTarget = urlUtils.parse(ctx._proxyTarget, true) 85 | proxyReqOpts.host = parsedTarget.hostname 86 | proxyReqOpts.port = parsedTarget.port 87 | proxyReqOpts.https = parsedTarget.protocol === 'https:' 88 | 89 | // 去掉Referer头,否则可能会造成CSRF问题,影响开发 90 | if (IS_DEBUG) { 91 | delete proxyReqOpts.headers.Referer 92 | delete proxyReqOpts.headers.Origin 93 | } 94 | // 计时开始 95 | ctx._proxyStartTime = Date.now() 96 | if (!needToken) { 97 | return proxyReqOpts 98 | } 99 | return await tokenManager.handleRequest(ctx) 100 | .then((additionalHeaders) => { 101 | Object.assign(proxyReqOpts.headers, additionalHeaders) 102 | }) 103 | .then(() => { 104 | return proxyReqOpts 105 | }) 106 | }, 107 | /** 108 | * 代理请求被响应后的回调 109 | * @param {Response} proxyRes - 代理请求选项 110 | * @param {Object} proxyResData - 响应数据 111 | * @param {ctx} ctx - koa ctx 112 | * @return {Promise.<*>} * 113 | */ 114 | async userResDecorator (proxyRes, proxyResData, ctx) { 115 | logger.info('ProxyRes headers:', '\n', JSON.stringify(ctx.response.headers, null, 2)) 116 | const location = `${ctx._proxyTarget}${ctx.url}` 117 | logger.info(`Proxy request '${location}' completed(${proxyRes.statusCode}), costing ${Date.now() - ctx._proxyStartTime}ms.`) 118 | if (!needToken) { 119 | return proxyResData 120 | } 121 | return await tokenManager.handleResponse(ctx) 122 | .then(() => { 123 | return proxyResData 124 | }) 125 | }, 126 | }), 127 | ]) 128 | } 129 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/utils/proxyMiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * http代理中间件 匹配代理、请求重定向 3 | * 获取app.config.js配置文件,匹配proxy 4 | */ 5 | const path = require('path') 6 | const urlUtils = require('url') 7 | const koaHttpProxy = require('koa-better-http-proxy') 8 | const compose = require('koa-compose') 9 | const appConfig = require('./../../app.config') 10 | const { IS_DEBUG } = require('./env') 11 | const logger = require('./logger/koa-logger')('proxyMiddleWare') 12 | 13 | const needToken = !!appConfig.token 14 | let tokenManager 15 | if (needToken) { 16 | tokenManager = require('./token')(appConfig.token) 17 | } 18 | 19 | /** 20 | * 获取代理配置 21 | * @return {*} 代理配置 22 | */ 23 | function getProxyConfig () { 24 | // 开发模式每次重新读取 25 | if (!IS_DEBUG) { 26 | return appConfig.proxy 27 | } 28 | // 生产环境读取 29 | const serverConfig = require(path.join(process.cwd(), 'server.config.js')) 30 | return serverConfig.proxy 31 | } 32 | 33 | /** 34 | * 代理处理中间件 35 | * @return {Function} koa middleware 36 | */ 37 | module.exports = function () { 38 | async function preProxyMiddleware (ctx, next) { 39 | const url = ctx.url 40 | logger.info(`Request '${url}'`) 41 | let proxyTarget 42 | let proxyConfig = getProxyConfig() 43 | // 在appConfig.proxy中寻找匹配前缀的代理 44 | for (const [prefix, target] of Object.entries(proxyConfig)) { 45 | if (url.startsWith(prefix)) { 46 | // 匹配替换 47 | if (!IS_DEBUG) { 48 | ctx.url = url.replace(prefix, '') 49 | } 50 | proxyTarget = target 51 | ctx._proxyTarget = proxyTarget 52 | 53 | logger.info(`Match to proxy: '${prefix}' => '${proxyTarget}'`) 54 | break 55 | } 56 | } 57 | if (!proxyTarget) { 58 | logger.info('Proxy not found, skipped') 59 | return Promise.resolve() 60 | } 61 | logger.info(`Will be Agent to '${proxyTarget + ctx.url}'`) 62 | return next() 63 | } 64 | 65 | /** 66 | * 顺序执行async函数 67 | */ 68 | return compose([ 69 | preProxyMiddleware, 70 | koaHttpProxy( 71 | (ctx) => { 72 | return ctx._proxyTarget 73 | }, 74 | { 75 | // 不解析body,不限制body大小 76 | parseReqBody: false, 77 | /** 78 | * 发出代理请求前的回调,更改头文件 79 | * @param {Object} proxyReqOpts - 代理请求选项 80 | * @param {ctx} ctx - koa ctx 81 | * @return {Promise.<*>} * 82 | */ 83 | async proxyReqOptDecorator (proxyReqOpts, ctx) { 84 | const parsedTarget = urlUtils.parse(ctx._proxyTarget, true) 85 | proxyReqOpts.host = parsedTarget.hostname 86 | proxyReqOpts.port = parsedTarget.port 87 | proxyReqOpts.https = parsedTarget.protocol === 'https:' 88 | 89 | // 去掉Referer头,否则可能会造成CSRF问题,影响开发 90 | if (IS_DEBUG) { 91 | delete proxyReqOpts.headers.Referer 92 | delete proxyReqOpts.headers.Origin 93 | } 94 | // 计时开始 95 | ctx._proxyStartTime = Date.now() 96 | if (!needToken) { 97 | return proxyReqOpts 98 | } 99 | return await tokenManager.handleRequest(ctx) 100 | .then((additionalHeaders) => { 101 | Object.assign(proxyReqOpts.headers, additionalHeaders) 102 | }) 103 | .then(() => { 104 | return proxyReqOpts 105 | }) 106 | }, 107 | /** 108 | * 代理请求被响应后的回调 109 | * @param {Response} proxyRes - 代理请求选项 110 | * @param {Object} proxyResData - 响应数据 111 | * @param {ctx} ctx - koa ctx 112 | * @return {Promise.<*>} * 113 | */ 114 | async userResDecorator (proxyRes, proxyResData, ctx) { 115 | logger.info('ProxyRes headers:', '\n', JSON.stringify(ctx.response.headers, null, 2)) 116 | const location = `${ctx._proxyTarget}${ctx.url}` 117 | logger.info(`Proxy request '${location}' completed(${proxyRes.statusCode}), costing ${Date.now() - ctx._proxyStartTime}ms.`) 118 | if (!needToken) { 119 | return proxyResData 120 | } 121 | return await tokenManager.handleResponse(ctx) 122 | .then(() => { 123 | return proxyResData 124 | }) 125 | }, 126 | }), 127 | ]) 128 | } 129 | -------------------------------------------------------------------------------- /webpack4-ssr-config/pm2.md: -------------------------------------------------------------------------------- 1 | # pm2 2 | 3 | #### 安装 4 | 5 | ```npm 6 | npm install pm2 -g // sudo 7 | ``` 8 | 9 | #### 1、常用命令 10 | 11 | * pm2 start app.js # 启动,守护进程。自动重启应用程序,加环境变量,比如配置 env_pro --> 加 --env pro 12 | * pm restart # 重启 13 | * pm2 stop # 停止 参数 = id|name|all|json|stdin 14 | * pm2 delete| del # 删除 参数 = name|id|script|all|json|stdin 15 | 16 | #### 2、集群模式 17 | 18 | * pm2 start app.js -i 4 # 参数 = 数字|max 在集群模式下,启动4个应用程序实例 同时,将网络请求,负载均衡到每个应用实例 19 | 20 | * pm2 reload all # 0秒重启所有应用 21 | 22 | pm2 scale appName 10 # 将应用进程调整到10 23 | 24 | * pm2 reset appName # 重置所有计数器 25 | 26 | #### 3、 进程监控 27 | 28 | * pm2 list|ls # 列出所有用PM2启动的进程 29 | * pm2 monit # 显示每个应用占用的cpu和内存 30 | * pm2 show appName or id # 显示某个进程的所有信息 31 | 32 | #### 4、日志管理 33 | 34 | * pm2 logs # 显示所有应用的日志 35 | 36 | * pm2 logs appName # 显示某个应用的日志 37 | 38 | * pm2 logs --json # json化日志 39 | 40 | * pm2 flush # 刷新日志 41 | 42 | * pm2 reloadLogs # 重新加载所有日志 43 | 44 | #### 5、启动/引导管理 45 | 46 | * pm2 startup # 检测init系统,在启动时生成和配置pm2 47 | * pm2 save # 保存当前进程列表 48 | * pm2 resurrect # 恢复以前保存的进程。 49 | * pm2 unstartup # 停用和删除启动系统 50 | * pm2 update # 保存进程,终止PM2并恢复进程 51 | * pm2 generate # 生成样本json配置文件。 52 | 53 | #### 6、部署 54 | 55 | * pm2 deploy app.json prod setup # 设置“生产环境”远程服务器。 56 | * pm2 deploy app.json prod # 更新“生产环境”远程服务器。 57 | * pm2 deploy app.json prod revert 2 # 将“生产环境”远程服务器恢复2。 58 | 59 | #### 7、模块系统 60 | 61 | * pm2 module:generate [name] # 生成名称为[name]的示例模块。 62 | * pm2 install pm2-logrotate # 安装模块(这里是日志循环系统)。 63 | * pm2 uninstall pm2-logrotate # 卸载模块。 64 | * pm2 publish # 增量版本,git push和npm发布。 65 | 66 | 67 | 68 | options具有以下选项的对象(这些选项的其他说明在此处): 69 | 70 | - `name` - 可用于在其他命令中稍后与进程交互(例如,重新启动)的任意名称。默认为脚本名称,不带其扩展名(例如`"testScript"`for `"testScript.js"`)。 71 | - `script` - 要运行的脚本的路径。 72 | - `args` - 由传递给脚本的参数组成的字符串或字符串数组。 73 | - `interpreterArgs` - 由调用解释器进程的参数组成的字符串或字符串数组。例如“-harmony”或[“-harmony”,“ - debug”]。仅适用`interpreter`于“none”以外的其他内容(默认情况下为“节点”)。 74 | - `cwd` - 用于启动进程的工作目录。 75 | - `output`- (默认值`"~/.pm2/logs/app_name-out.log"`:)将stdout输出追加到的文件的路径。可以是同一个文件`error`。 76 | - `error`- (默认值`"~/.pm2/logs/app_name-error.err"`:)将stderr输出附加到的文件的路径。可以是同一个文件`output`。 77 | - `logDateFormat` - 日志时间戳的显示格式(例如“YYYY-MM-DD HH:mm Z”)。格式是[时刻显示格式](http://momentjs.com/docs/#/displaying/)。 78 | - `pid`- (默认值`"~/.pm2/pids/app_name-id.pid"`:)用于写入已启动进程的pid的文件的路径。该文件将被覆盖。请注意,pm2不会以任何方式使用该文件,因此用户可以随时自由操作或删除该文件。当进程停止或守护程序被终止时,将删除该文件。 79 | - `minUptime` - 脚本在成功启动之前的最短正常运行时间。 80 | - `maxRestarts`- 如果脚本以小于的速率退出,则将重新启动脚本的最大行数`min_uptime`。 81 | - `maxMemoryRestart`- 如果设置和`script`内存使用量与配置的数量有关,则pm2重新启动`script`。使用人性化的后缀:'K'表示千字节,“M”表示兆字节,“G”表示千兆字节等。例如“150M”。 82 | - killTimeout`- (默认值:)`1600`在`stop`或`restart`命令发出`SIGINT`信号以强制使用`SIGKILL`信号终止脚本之后等待的毫秒数。 83 | - `restartDelay`- (默认值`0`:)重新启动已退出的脚本之前等待的毫秒数。 84 | - `interpreter`- (默认值`'node'`:)脚本的解释器(例如“python”,“ruby”,“bash”等)。值“none”将执行“脚本”作为二进制可执行文件。 85 | - `execMode`- (默认值:) `'fork'`如果设置为'cluster',将启用群集(运行多个实例`script`)。[在这里看到更多的细节](http://pm2.keymetrics.io/docs/usage/cluster-mode/)。 86 | - `instances`- (*默认值1* :) `script`要创建的实例数。仅与`exec_mode`'集群' 相关。 87 | - `mergeLogs`- (默认值`false`:)如果为true,则将所有实例的日志文件合并`script`为一个stderr日志和一个stdout日志。仅适用于“群集”模式。例如,如果您通过pm2启动了4个'test.js'实例,通常会有4个stdout日志文件和4个stderr日志文件,但是如果将此选项设置为true,则只有一个stdout文件和一个stderr文件。 88 | - `watch`- 如果设置为`true`,则在更改`script`文件时将重新启动应用程序。 89 | - `force`(默认值`false`:)默认情况下,pm2仅在该脚本尚未运行时才启动脚本(脚本是应用程序的路径,而不是已运行的应用程序的名称)。如果`force`设置为true,则pm2将启动该脚本的新实例。 90 | - `autorestart`(默认`true`)。如果`false`,pm2 在成功完成或进程失败后将*不会*尝试重新启动它。 91 | - `cron` 92 | - `executeCommand` 93 | - `write` 94 | - `sourceMapSupport` 95 | - `disableSourceMapSupport` 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /webpack4-basic-config/config/webpack.config.base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack base配置 3 | * Created by zdliu on 2018/7/6. 4 | */ 5 | const appConfig = require('./../app.config') 6 | const path = require('path') 7 | const webpack = require('webpack') 8 | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const vueLoaderPlugin = require('vue-loader/lib/plugin') 11 | const ExtractCssChunks = require("extract-css-chunks-webpack-plugin") 12 | const merge = require('webpack-merge') 13 | const vendorsManifest = require(path.join(process.cwd(), 'vendors-manifest.json')) 14 | 15 | const isProd = process.env.NODE_ENV === 'production' 16 | 17 | // 版本号 18 | const appVersion = new Date().getTime() 19 | 20 | function resolve(dir) { 21 | return path.resolve(process.cwd(), dir) 22 | } 23 | 24 | // 网站图标 25 | const favicon = path.join(process.cwd(), 'favicon.ico') 26 | 27 | module.exports = function () { 28 | const config = merge(appConfig.webpack, { 29 | // 输出模块配置 30 | output: { 31 | // 输出到这个目录下 32 | path: resolve('dist'), 33 | // 生成的文件名, [name] 即为entry配置中的key 34 | filename: `[name].[${isProd ? 'chunkhash' : 'hash'}:8].js`, 35 | // 异步模块文件名 36 | chunkFilename: '[id].js', 37 | publicPath: '/' 38 | }, 39 | // 寻找模块时的一些缺省设置 40 | resolve: { 41 | // 补充扩展名 42 | extensions: ['.js', '.vue', '.json'], 43 | // 别名,可以直接使用别名来代表设定的路径以及其他 44 | alias: { 45 | 'vue': 'vue/dist/vue.esm.js', 46 | '@': resolve('src'), 47 | '@config': resolve('config'), 48 | } 49 | }, 50 | module: { 51 | rules: [ 52 | { 53 | test: /\.vue$/, 54 | use: ['vue-loader', 'eslint-loader'] 55 | }, 56 | // js,jsx 转译 57 | { 58 | test: /\.(js|jsx)$/, 59 | use: ['babel-loader'], 60 | exclude: /node_modules/, 61 | }, 62 | { 63 | test: /\.css$/, 64 | use: [isProd ? ExtractCssChunks.loader : 'vue-style-loader', 'css-loader', 'postcss-loader'] 65 | }, 66 | { 67 | test: /\.(styl|stylus)$/, 68 | use: [isProd ? ExtractCssChunks.loader : 'vue-style-loader', 'css-loader', 'postcss-loader', 69 | { 70 | loader: 'stylus-loader', 71 | options: isProd ? {} : {sourceMap: 'inline'} 72 | } 73 | ] 74 | }, 75 | { 76 | test: /\.json$/, 77 | use: 'json-loader', 78 | }, 79 | // 图片资源 gif|jpg|jpeg|png|bmp|svg|ico 80 | { 81 | test: /\.(gif|jpg|jpeg|png|bmp|svg|ico)(\?.*)?$/, 82 | use: [{ 83 | loader: 'url-loader', 84 | options: { 85 | limit: 1, 86 | name: 'assets/images/[name].[hash:8].[ext]', 87 | }, 88 | }], 89 | }, 90 | // 字体文件 woff|woff2|eot|ttf 91 | { 92 | test: /\.(woff|woff2|eot|ttf)(\?.*)?$/, 93 | use: [{ 94 | loader: 'url-loader', 95 | options: { 96 | // 小于8912字节的文件,返回dataurl 97 | limit: 8912, 98 | // 生成的文件名,[name]为原始文件名,[hash:8]为根据文件内容生成8位md5值,[ext]为原始文件扩展名 99 | name: 'assets/font/[name].[hash:8].[ext]', 100 | }, 101 | }], 102 | }, 103 | ], 104 | }, 105 | performance: { 106 | maxEntrypointSize: 300000, 107 | hints: false 108 | }, 109 | plugins: [ 110 | // 由于mac不区分大小写,linux区分大小写,可能导致mac上正常,在部署时出错,所以强制区分大小写 111 | new CaseSensitivePathsPlugin(), 112 | // // 读取HTML模板文件,并输出HTML文件,开发环境实际输出到内存中 113 | new HtmlWebpackPlugin({ 114 | appVersion, 115 | favicon, 116 | filename: 'index.html', 117 | dllSrc: `/${vendorsManifest.name}.dll.js`, 118 | template: path.join(process.cwd(), 'index.template.ejs'), 119 | inject: true, 120 | // minify: { 121 | // removeComments: true, //去注释 122 | // collapseWhitespace: true, //压缩空格 123 | // }, 124 | }), 125 | new webpack.DllReferencePlugin({ 126 | context: path.join(process.cwd()), 127 | manifest: path.join(process.cwd(), 'vendors-manifest.json'), 128 | }), 129 | new vueLoaderPlugin(), 130 | new webpack.optimize.LimitChunkCountPlugin({ 131 | maxChunks: 1 132 | }) 133 | ], 134 | }) 135 | return config 136 | } --------------------------------------------------------------------------------