├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── 1.png ├── 2.png ├── 3.png ├── README.md ├── app.js ├── bin ├── build.js ├── dev.js └── server.js ├── package-lock.json ├── package.json ├── readfiles.js ├── src ├── assets │ ├── css │ │ └── common.scss │ └── image │ │ ├── empty_ysd.png │ │ └── timg.jpg ├── common │ ├── App.vue │ └── index.js ├── components │ ├── alert.vue │ ├── titlerefresher.vue │ └── toast.js ├── features │ ├── login │ │ ├── home.vue │ │ ├── main.js │ │ └── router.js │ ├── test │ │ ├── container │ │ │ ├── test.vue │ │ │ └── test1.vue │ │ ├── home.vue │ │ ├── main.js │ │ ├── module │ │ │ └── test1.js │ │ ├── router.js │ │ └── store │ │ │ └── index.js │ └── test1 │ │ ├── container │ │ └── test.vue │ │ ├── home.vue │ │ ├── main.js │ │ ├── router.js │ │ └── store │ │ └── index.js └── pluges │ ├── filter.js │ ├── service.js │ ├── store.js │ └── vuexMap.js ├── view ├── login.html ├── test.html └── test1.html ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"], 3 | "plugins": [ 4 | "transform-runtime", 5 | "transform-vue-jsx", 6 | "transform-decorators-legacy" 7 | ], 8 | "comments": false 9 | } 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | dist/ 3 | node_modules/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 7 | extends: 'standard', 8 | parser: "babel-eslint", 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | "no-eval": 0, 16 | // allow paren-less arrow functions 17 | 'arrow-parens': 0, 18 | // allow debugger during development 19 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 20 | "eqeqeq": 0,//必须使用全等 21 | "no-multi-spaces":0, 22 | "indent":0, 23 | "comma-dangle": [2, "only-multiline"], //定义数组或对象最后多余的逗号 24 | "no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuobeige11/vue-genection/007004427e04b3e493149e5828cb074fd245f2d5/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuobeige11/vue-genection/007004427e04b3e493149e5828cb074fd245f2d5/2.png -------------------------------------------------------------------------------- /3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuobeige11/vue-genection/007004427e04b3e493149e5828cb074fd245f2d5/3.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 基于VUE2.0, VUE-Route实现的多页脚手架 3 | 4 | 适用于混合式app下的多页面入口及分模块发布 5 | 6 | 多页下单路由配置基与 children 实现 7 | 8 | ![image](1.png) 9 | 10 | 11 | ![image](3.png) 12 | 13 | 14 | 15 | 16 | ### 服务端配置 17 | 18 | nginx: 19 | 20 | ![image](2.png) 21 | 22 | node: (参考bin文件夹下dev.js配置: 基于express路由配置) 23 | 24 | ### 开发目录 25 | ``` 26 | . 27 | ├── README.md 28 | ├── bin 29 | │   ├── dev.js 30 | │   └── build.js 31 | │   └── server.js 32 | ├── redfiles.js(遍历目录) 33 | ├── app.js 34 | ├── dist(打包目录) 35 | ├── webpack.dev.conf.js 36 | ├── webpack.prod.conf.js 37 | ├── package-lock.json 38 | ├── package.json 39 | ├── src 40 | │   ├── features 41 | │      ├── test 42 | | | └── container 43 | | | └── store 44 | | | └── App.vue 45 | | | └── home.vue 46 | | | └── router.js 47 | | | └── main.js 48 | │      ├── test2 49 | | | └── container 50 | | | └── store 51 | | | └── App.vue 52 | | | └── home.vue 53 | | | └── router.js 54 | | | └── main.js 55 | │   ├── components(公共组件) 56 | │   └── common(公共方法) 57 | │   └── pluges(中间件) 58 | ├── view 59 | │   ├── test.html 60 | │   ├── test2.html 61 | ``` 62 | 63 | 64 | 65 | 66 | 67 | ---- 68 | 69 | 启动程序 70 | ``` bash 71 | 72 | # serve with hot reload at localhost:8083 73 | npm run dev 74 | 75 | # build for production with minification 76 | npm run build 77 | 78 | ``` 79 | 80 | ---- 81 | 82 | 83 | ### 结语 84 | + 拓展方向(结合nuxt做服务端渲染) 85 | + 单页面下可以引入vuex 86 | 87 | ... 88 | 89 | 👍👍👍 90 | 91 | 92 | ---- 93 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | const express = require('express'); 3 | const path = require('path'); 4 | const bodyParser = require('body-parser'); 5 | const ejs = require('ejs'); 6 | 7 | const app = express(); 8 | 9 | 10 | app.engine('html', ejs.__express); 11 | app.set('views', path.join(__dirname, 'view')); 12 | app.set('view engine', 'html'); 13 | 14 | app.use(bodyParser.json()); 15 | app.use(bodyParser.urlencoded({ extended: false })); 16 | 17 | app.use(express.static(path.join(__dirname, 'static'))); 18 | 19 | 20 | //安全设置, 21 | //禁用x-powered-by 头 22 | //禁止任何frame,iframe,xss protections 23 | 24 | 25 | module.exports = app; -------------------------------------------------------------------------------- /bin/build.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var config = require("../webpack.prod.conf"); 3 | 4 | var compiler = webpack(config, function(err, stats) { 5 | if (err) throw err; 6 | process.stdout.write( 7 | stats.toString({ 8 | colors: true, 9 | modules: false, 10 | children: false, 11 | chunks: false, 12 | chunkModules: false 13 | }) 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /bin/dev.js: -------------------------------------------------------------------------------- 1 | require("babel-register"); 2 | require("babel-polyfill"); 3 | require("./server"); 4 | 5 | var webpack = require("webpack"); 6 | var webpackDevMiddleware = require("webpack-dev-middleware"); 7 | var webpackHotMiddleware = require("webpack-hot-middleware"); 8 | var config = require("../webpack.dev.conf"); 9 | var fileReder = require("../readfiles"); 10 | var files = fileReder("./src/features"); 11 | var proxyMiddleware = require("http-proxy-middleware"); 12 | var proxyTable = require("./config/dev").default; 13 | proxyTable = proxyTable.proxyTable; 14 | 15 | var app = require("../app"); 16 | 17 | var compiler = webpack(config); 18 | 19 | const serverOption = { 20 | publicPath: config.output.publicPath, 21 | stats: { 22 | colors: true, 23 | chunks: false 24 | } 25 | }; 26 | 27 | Object.keys(proxyTable).forEach(context => { 28 | let options = proxyTable[context]; 29 | if (typeof options === "string") { 30 | options = { target: options }; 31 | } 32 | app.use(proxyMiddleware(options.filter || context, options)); 33 | }); 34 | 35 | app.use(webpackDevMiddleware(compiler, serverOption)); 36 | app.use(webpackHotMiddleware(compiler)); 37 | app.use((req, res, next) => { 38 | if (req.headers.accept.match("text/html")) { 39 | res.header("Content-Type", "text/html; charset=utf-8"); 40 | return next(); 41 | } 42 | return next(); 43 | }); 44 | 45 | files.forEach(data => { 46 | app.get("/" + data, (req, res) => { 47 | res.render(data); 48 | }); 49 | app.get("/" + data + "/:siteId", (req, res) => { 50 | res.render(data); 51 | }); 52 | app.get("/" + data + "/:siteId/:pageId", (req, res) => { 53 | res.render(data); 54 | }); 55 | app.get("/" + data + "/:siteId/:pageId/:nameId", (req, res) => { 56 | res.render(data); 57 | }); 58 | app.get("/" + data + "/:siteId/:pageId/nameId/nameId1", (req, res) => { 59 | res.render(data); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /bin/server.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var app = require('../app'); 4 | var debug = require('debug'); 5 | var http = require('http'); 6 | 7 | var port = normalizePort(process.env.PORT || '8083'); 8 | app.set('port', port); 9 | 10 | /** 11 | * Create HTTP server. 12 | */ 13 | 14 | var server = http.createServer(app); 15 | 16 | /** 17 | * Listen on provided port, on all network interfaces. 18 | */ 19 | 20 | server.listen(port); 21 | server.on('error', onError); 22 | server.on('listening', onListening); 23 | 24 | /** 25 | * Normalize a port into a number, string, or false. 26 | */ 27 | 28 | function normalizePort(val) { 29 | var port = parseInt(val, 10); 30 | 31 | if (isNaN(port)) { 32 | // named pipe 33 | return val; 34 | } 35 | 36 | if (port >= 0) { 37 | // port number 38 | return port; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | /** 45 | * Event listener for HTTP server "error" event. 46 | */ 47 | 48 | function onError(error) { 49 | if (error.syscall !== 'listen') { 50 | throw error; 51 | } 52 | 53 | var bind = typeof port === 'string' 54 | ? 'Pipe ' + port 55 | : 'Port ' + port; 56 | 57 | // handle specific listen errors with friendly messages 58 | switch (error.code) { 59 | case 'EACCES': 60 | console.error(bind + ' requires elevated privileges'); 61 | process.exit(1); 62 | break; 63 | case 'EADDRINUSE': 64 | console.error(bind + ' is already in use'); 65 | process.exit(1); 66 | break; 67 | default: 68 | throw error; 69 | } 70 | } 71 | 72 | /** 73 | * Event listener for HTTP server "listening" event. 74 | */ 75 | 76 | function onListening() { 77 | var addr = server.address(); 78 | var bind = typeof addr === 'string' 79 | ? 'pipe ' + addr 80 | : 'port ' + addr.port; 81 | debug('test:server')('Listening on ' + bind); 82 | console.log('serve start on: %s', bind); 83 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vues", 3 | "version": "1.0.0", 4 | "description": "vues 2.0", 5 | "author": "weichangbin", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env CODE_ENV=dev node bin/dev.js", 9 | "build": "rimraf ./dist && node bin/build.js", 10 | "deploy_dev": "cross-env CODE_ENV=dev npm run build && ymm_upload -r ./dist -n ymm-boss-component -t dev -z 0", 11 | "deploy_beta": "cross-env CODE_ENV=beta npm run build:entry-all && ymm_upload -r ./dist -n ymm-boss-component -t beta -z 0", 12 | "deploy_prod": "cross-env CODE_ENV=production npm run build:entry-all && ymm_upload -r ./dist -n ymm-boss-component -t release -z 1", 13 | "test": "jest", 14 | "lint": "eslint --ext .js,.vue src test/e2e/specs" 15 | }, 16 | "dependencies": { 17 | "axios": "^0.17.1", 18 | "babel": "^6.23.0", 19 | "babel-loader": "^7.1.5", 20 | "babel-plugin-component": "^1.1.0", 21 | "babel-plugin-transform-react-jsx": "^6.24.1", 22 | "element-ui": "^2.2.2", 23 | "eslint": "^5.4.0", 24 | "eslint-config-standard": "^12.0.0-alpha.0", 25 | "eslint-plugin-html": "^4.0.5", 26 | "eslint-plugin-import": "^2.14.0", 27 | "eslint-plugin-node": "^7.0.1", 28 | "eslint-plugin-promise": "^4.0.0", 29 | "eslint-plugin-standard": "^3.1.0", 30 | "file-loader": "^1.1.11", 31 | "html-webpack-plugin": "^2.30.1", 32 | "jest": "^22.0.5", 33 | "mint-ui": "^2.2.13", 34 | "transform-runtime": "0.0.0", 35 | "uglifyjs-webpack-plugin": "^1.2.2", 36 | "url-loader": "^0.6.2", 37 | "vue": "^2.5.17", 38 | "vue-loader": "^13.7.2", 39 | "vue-property-decorator": "^7.0.0", 40 | "vue-router": "^3.0.1", 41 | "vue-template-compiler": "^2.5.17", 42 | "vuex": "^3.0.1", 43 | "vuex-router-sync": "^5.0.0", 44 | "webpack": "^3.12.0" 45 | }, 46 | "devDependencies": { 47 | "autoprefixer": "^6.7.7", 48 | "babel-core": "^6.26.0", 49 | "babel-eslint": "^7.2.3", 50 | "babel-helper-vue-jsx-merge-props": "^2.0.1", 51 | "babel-plugin-syntax-jsx": "^6.18.0", 52 | "babel-plugin-transform-decorators-legacy": "^1.3.5", 53 | "babel-plugin-transform-runtime": "^6.23.0", 54 | "babel-plugin-transform-vue-jsx": "^3.7.0", 55 | "babel-polyfill": "^6.26.0", 56 | "babel-preset-es2015": "^6.24.1", 57 | "babel-preset-stage-0": "^6.24.1", 58 | "babel-preset-stage-2": "^6.0.0", 59 | "babel-register": "^6.26.0", 60 | "bluebird": "^3.5.1", 61 | "body-parser": "^1.17.1", 62 | "cross-env": "^5.2.0", 63 | "css-loader": "^0.25.0", 64 | "ejs": "^2.6.1", 65 | "eslint-friendly-formatter": "^4.0.1", 66 | "eslint-loader": "^2.1.0", 67 | "express": "^4.16.3", 68 | "extract-text-webpack-plugin": "^1.0.1", 69 | "http-proxy-middleware": "^0.18.0", 70 | "json-loader": "^0.5.4", 71 | "node-sass": "^4.9.3", 72 | "sass-loader": "^6.0.7", 73 | "scss-loader": "0.0.1", 74 | "style-loader": "^0.16.1", 75 | "vue-style-loader": "^1.0.0", 76 | "webpack-dev-middleware": "^1.12.2", 77 | "webpack-hot-middleware": "^2.22.3" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /readfiles.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | 4 | function readfiles(path) { 5 | return fs.readdirSync(path); 6 | } 7 | 8 | module.exports = paths => { 9 | let entry = [] 10 | paths = path.resolve(__dirname, paths) 11 | if (fs.statSync(paths).isDirectory()) { 12 | let files = readfiles(paths) 13 | let states = fs.statSync(paths) 14 | files.forEach(function(file){ 15 | if (states.isDirectory() && paths) { 16 | entry.push(file) 17 | } 18 | }); 19 | entry = entry.filter(data => data != '.DS_Store') 20 | return entry 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/assets/css/common.scss: -------------------------------------------------------------------------------- 1 | html, body, div, span, header, section, div, p, ul, li, dl, dd, a, input, i, textarea { 2 | margin:0; 3 | padding:0; 4 | list-style:none; 5 | border:0; 6 | font-style:normal; 7 | -webkit-appearance: none; 8 | -webkit-tap-highlight-color: rgba(255,255,255,0); 9 | } 10 | em, dfn { 11 | font-style:normal 12 | } 13 | html { 14 | height: 100%; 15 | } 16 | 17 | body { 18 | font-family:Microsoft Yahei, sans-serif; 19 | line-height: 1.5; 20 | font-size: 12px; 21 | color: #444; 22 | user-select: none; 23 | text-size-adjust: 100%; 24 | width: 100%; 25 | overflow-x: hidden; 26 | background:#f3f3f3; 27 | height:100%; 28 | 29 | 30 | } 31 | 32 | a { 33 | color:#444; 34 | text-decoration:none 35 | } -------------------------------------------------------------------------------- /src/assets/image/empty_ysd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuobeige11/vue-genection/007004427e04b3e493149e5828cb074fd245f2d5/src/assets/image/empty_ysd.png -------------------------------------------------------------------------------- /src/assets/image/timg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuobeige11/vue-genection/007004427e04b3e493149e5828cb074fd245f2d5/src/assets/image/timg.jpg -------------------------------------------------------------------------------- /src/common/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 26 | -------------------------------------------------------------------------------- /src/common/index.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | codeMsg: '' 3 | } 4 | 5 | const getters = { 6 | codeMsg: state => state.codeMsg 7 | } 8 | 9 | const mutations = { 10 | API_FALID (state, { data }) { 11 | state.codeMsg = data 12 | }, 13 | API_MSG_CLEAR (state) { 14 | state.codeMsg = '' 15 | } 16 | } 17 | 18 | const actions = { 19 | msgClear ({ commit, state }) { 20 | commit('API_MSG_CLEAR') 21 | }, 22 | alertshow ({ commit, state }, data) { 23 | commit('API_FALID', { data }) 24 | } 25 | } 26 | 27 | export default { 28 | state, 29 | getters, 30 | mutations, 31 | actions 32 | } 33 | -------------------------------------------------------------------------------- /src/components/alert.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/titlerefresher.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /src/components/toast.js: -------------------------------------------------------------------------------- 1 | function show () { 2 | const loader = document.querySelector('.uiLoadingBlock') 3 | if (loader) { 4 | loader.setAttribute('class', 'uiLoadingBlock show') 5 | return 6 | } 7 | const htmlStr = `
8 | 9 |
` 10 | const div = document.createElement('div') 11 | div.setAttribute('class', 'uiLoadingBlock show') 12 | div.innerHTML = htmlStr 13 | document.body.appendChild(div) 14 | } 15 | 16 | function hide () { 17 | const loader = document.querySelector('.uiLoadingBlock') 18 | if (!loader) return 19 | loader.setAttribute('class', 'uiLoadingBlock') 20 | } 21 | 22 | function css () { 23 | return `.loading{ 24 | display: flex; 25 | box-pack: center; 26 | box-align: center; 27 | text-align: center; 28 | height: 40px; 29 | } 30 | .uiLoading{ 31 | width: 20px; 32 | height: 20px; 33 | display: block; 34 | background: url("../assets/img/loading_sprite.png"); 35 | background-size: auto 20px; 36 | animation: am-rotate 1s steps(12) infinite; 37 | } 38 | .uiLoadingBright{ 39 | width: 37px; 40 | height: 37px; 41 | display: block; 42 | background-image: url("data:image/png;base64,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"); 43 | background-size: auto 37px; 44 | animation: am-rotate2 1s steps(12) infinite; 45 | 46 | } 47 | .loading .uiLoading{margin: 10px;} 48 | .uiLoadingBlock{ 49 | position: fixed; 50 | top: 0; 51 | width: 100%; 52 | height: 100%; 53 | z-index: 100000; 54 | display:flex; 55 | align-items: center; 56 | justify-content: center; 57 | box-orient: horizontal; 58 | box-pack: center; 59 | box-align: center; 60 | background: rgba(0,0,0,.4); 61 | background: rgba(0,0,0,0); 62 | display:none; 63 | 64 | } 65 | 66 | .uiLoadingBlock .uiLoadingCnt{ 67 | width: 86px; 68 | height: 86px; 69 | display: flex; 70 | text-align: center; 71 | align-items: center; 72 | background: rgba(0,0,0,.65); 73 | border-radius: 6px; 74 | color: #fff; 75 | 76 | } 77 | .uiLoadingBlock .uiLoadingBright{ 78 | margin:0 auto 79 | } 80 | 81 | .uiLoadingBlock.show{ 82 | display: flex; 83 | } 84 | 85 | @-webkit-keyframes am-rotate { 86 | from { 87 | background-position: 0 0; 88 | } 89 | 90 | to { 91 | background-position: -240px 0; 92 | } 93 | } 94 | @-webkit-keyframes am-rotate2 { 95 | from { 96 | background-position: 0 0; 97 | } 98 | 99 | to { 100 | background-position: -444px 0; 101 | } 102 | }` 103 | } 104 | 105 | export default { 106 | show, 107 | hide 108 | } 109 | -------------------------------------------------------------------------------- /src/features/login/home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 22 | -------------------------------------------------------------------------------- /src/features/login/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import MintUI from 'mint-ui' 4 | import axios from 'axios' 5 | import Router from './router' 6 | import Home from './Home' 7 | 8 | Vue.use(VueRouter) 9 | Vue.use(plugin) 10 | Vue.use(MintUI) 11 | 12 | const router = new VueRouter({ 13 | routes: Router() 14 | }) 15 | 16 | router.beforeEach((to, from, next) => { 17 | // 更改iframe src fix bug 18 | if (document.getElementById('title_refresher')) { 19 | let titleRefresher = document.getElementById('title_refresher') 20 | titleRefresher.src = '' 21 | } 22 | next() 23 | }) 24 | 25 | new Vue({ 26 | router, 27 | render: h => h(Home) 28 | }).$mount('#app') 29 | 30 | function plugin (Vue) { 31 | if (plugin.installed) { 32 | return 33 | } 34 | plugin.installed = true 35 | Object.defineProperties(Vue.prototype, { 36 | axios: { 37 | get () { 38 | return axios 39 | } 40 | } 41 | }) 42 | } 43 | if (typeof window !== 'undefined' && window.Vue) { 44 | window.Vue.use(plugin) 45 | } 46 | -------------------------------------------------------------------------------- /src/features/login/router.js: -------------------------------------------------------------------------------- 1 | const login = resolve => { 2 | require.ensure(['./home'], () => { 3 | resolve(require('./home')) 4 | }) 5 | } 6 | const routes = [ 7 | { 8 | path: '/login', 9 | component: login 10 | } 11 | ] 12 | 13 | export default () => routes 14 | -------------------------------------------------------------------------------- /src/features/test/container/test.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/features/test/container/test1.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/features/test/home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /src/features/test/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import MintUI from 'mint-ui' 4 | import axios from 'axios' 5 | import services from '../../pluges/service' 6 | import { store } from './store' 7 | import Router from './router' 8 | import App from '../../common/App' 9 | 10 | services(store) 11 | Vue.use(VueRouter) 12 | Vue.use(plugin) 13 | Vue.use(MintUI) 14 | 15 | const router = new VueRouter({ 16 | routes: Router() 17 | }) 18 | router.beforeEach((to, from, next) => { 19 | if (document.getElementById('title_refresher')) { 20 | let titleRefresher = document.getElementById('title_refresher') 21 | titleRefresher.src = '' 22 | } 23 | next() 24 | }) 25 | 26 | new Vue({ 27 | router, 28 | store, 29 | render: h => h(App) 30 | }).$mount('#app') 31 | 32 | function plugin (Vue) { 33 | if (plugin.installed) { 34 | return 35 | } 36 | plugin.installed = true 37 | Object.defineProperties(Vue.prototype, { 38 | axios: { 39 | get () { 40 | return axios 41 | } 42 | } 43 | }) 44 | } 45 | if (typeof window !== 'undefined' && window.Vue) { 46 | window.Vue.use(plugin) 47 | } 48 | -------------------------------------------------------------------------------- /src/features/test/module/test1.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const state = { 4 | list: [] 5 | } 6 | 7 | const getters = { 8 | list: state => state.list 9 | } 10 | 11 | const actions = { 12 | async getMessage () { 13 | let r = await axios.get('/') 14 | console.log(r) 15 | } 16 | } 17 | 18 | const mutations = { 19 | GET_API_TEST (state, data) { 20 | state.list = data 21 | } 22 | } 23 | 24 | export default { 25 | state, 26 | getters, 27 | actions, 28 | mutations 29 | } 30 | -------------------------------------------------------------------------------- /src/features/test/router.js: -------------------------------------------------------------------------------- 1 | const testRoute = resolve => { 2 | require.ensure(['./home'], () => { 3 | resolve(require('./home')) 4 | }) 5 | } 6 | const route2 = resolve => { 7 | require.ensure(['./container/test'], () => { 8 | resolve(require('./container/test')) 9 | }) 10 | } 11 | 12 | const route1 = resolve => { 13 | require.ensure(['./container/test1'], () => { 14 | resolve(require('./container/test1')) 15 | }) 16 | } 17 | 18 | const routes = [ 19 | { 20 | path: '/test', 21 | component: testRoute, 22 | children: [{ 23 | path: 'test1', 24 | component: route1 25 | }, { 26 | path: 'test2', 27 | component: route2 28 | }] 29 | } 30 | ] 31 | 32 | export default () => routes 33 | -------------------------------------------------------------------------------- /src/features/test/store/index.js: -------------------------------------------------------------------------------- 1 | import stores from '../../../pluges/store' 2 | import test1 from '../module/test1' 3 | export const store = stores({ 4 | test1 5 | }) 6 | -------------------------------------------------------------------------------- /src/features/test1/container/test.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /src/features/test1/home.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/features/test1/main.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue' 3 | import VueRouter from 'vue-router' 4 | import Mint from 'mint-ui' 5 | import services from '../../pluges/service' 6 | import { store } from './store' 7 | import Router from './router' 8 | import App from '../../common/App' 9 | Vue.use(VueRouter) 10 | Vue.use(services) 11 | Vue.use(Mint) 12 | 13 | const router = new VueRouter({ 14 | routes: Router(), 15 | mode: 'history' 16 | }) 17 | 18 | router.beforeEach((to, from, next) => { 19 | // 更改iframe src fix bug 20 | if (document.getElementById('title_refresher')) { 21 | let titleRefresher = document.getElementById('title_refresher') 22 | titleRefresher.src = '' 23 | } 24 | next() 25 | }) 26 | 27 | new Vue({ 28 | router, 29 | store, 30 | render: h => h(App) 31 | }).$mount('#app') 32 | -------------------------------------------------------------------------------- /src/features/test1/router.js: -------------------------------------------------------------------------------- 1 | const testRoute = resolve => { 2 | require.ensure(['./home'], () => { 3 | resolve(require('./home')) 4 | }) 5 | } 6 | const route2 = resolve => { 7 | require.ensure(['./container/test'], () => { 8 | resolve(require('./container/test')) 9 | }) 10 | } 11 | const routes = [ 12 | { 13 | path: '/test1', 14 | component: testRoute, 15 | children: [{ 16 | path: 'test1', 17 | component: route2 18 | }] 19 | } 20 | ] 21 | 22 | export default () => routes 23 | -------------------------------------------------------------------------------- /src/features/test1/store/index.js: -------------------------------------------------------------------------------- 1 | import stores from '../../../pluges/store' 2 | export const store = stores({}) 3 | -------------------------------------------------------------------------------- /src/pluges/filter.js: -------------------------------------------------------------------------------- 1 | const REGEXP_TELEPHONE = /^\d{3}-\d{8}$|^\d{4}-\d{7,8}$/ 2 | const REGEXP_MOBILE = /^1[34578]\d{9}$/ 3 | const REGEXP_USC = /^[^_IOZSVa-z\W]{2}\d{6}[^_IOZSVa-z\W]{10}$/ 4 | import moment from 'moment' 5 | 6 | /** 7 | * 8 | * @param item 9 | * @param val 10 | * @param hide 11 | * @return {Array} 12 | * @example 13 | * basic useage 14 | * let item = {key: contract, validator: {required: [true], rules: {phone: 'mobile'}, ignore: this.isCheck}}; 15 | * let val = '13770707613' 16 | * let invalidVal = '13770707' 17 | * validator(item, val) // => [] //ok 18 | * validator(item, invalidVal) // => ['phone'] //invalid 19 | * 20 | * 21 | * let hideItem = {required: true, rules: {phone: 'mobile'}}; 22 | * let invalidVal = '13770707' 23 | * validator(hideItem, invalidVal, true) // => [] //ok 24 | */ 25 | export const validator = (item, val, hide) => { 26 | if (Array.isArray(item)) { 27 | let ret = {} 28 | for (let i = 0, il = item.length; i < il; i++) { 29 | Object.assign(ret, handle(item[i], item[i].val, item[i].hide)) 30 | } 31 | return ret 32 | } else { 33 | return handle(item, val, hide) 34 | } 35 | } 36 | 37 | const handle = (item, val, hide) => { 38 | if (!item) return {} 39 | if (item.isRange && item.items.length) { 40 | let ret = {} 41 | for (let i = 0, il = item.items.length; i < il; i++) { 42 | Object.assign(ret, vali(item.items[i], item.items[i].val, item.items[i].hide)) 43 | } 44 | return ret 45 | } else { 46 | return vali(item, val, hide) 47 | } 48 | } 49 | 50 | const vali = (item, val, hide) => { 51 | let validatorRet = [] 52 | let ret = {} 53 | if (!item.validator || hide || item.validator.ignore) return ret 54 | // console.log(item.key, val) 55 | if (item.validator.rules && !Object.keys(item.validator.rules).length) { 56 | console.error('validator need params', item) 57 | return ret 58 | } 59 | if (item.validator.required && item.validator.required[0]) { 60 | if (val === '' || val === null || val === undefined || (typeof val === 'object' && Object.keys(val).length < 1)) { 61 | validatorRet.push(item.validator.required[1] || '必填') 62 | ret[item.key] = validatorRet 63 | return ret 64 | } 65 | } 66 | for (const rule in item.validator.rules) { 67 | let params = item.validator.rules[rule] 68 | /** 69 | * array_len_range:[min[, max, tips]] 70 | */ 71 | if (rule === 'array_len_range') { 72 | if (!Array.isArray(val)) throw new Error('validator array_len_range need a array') 73 | if (!params.length || params[0] < 0 || params[1] < 0) throw new Error('validator array_len_range need params') 74 | let min = Math.max(0, params[0]) 75 | if (val.length < min || (params[1] && val.length > params[1])) { 76 | validatorRet.push(params[2] || (params[1] ? `请填写${min} ~ ${params[1]}` : `请至少选择${min}个`)) 77 | } 78 | } 79 | /** 80 | * str_len_range:[min, max[, tips]] 81 | * { 82 | title: '公司名称', 83 | type: 'input', 84 | key: 'companyName', 85 | val: '', 86 | validator: {required: [true], rules: {str_len_range: [2, 30]}, ignore: this.isCheck} 87 | }, 88 | */ 89 | if (rule === 'str_len_range') { 90 | if (!params.length || params[0] < 0 || !params[1]) throw new Error('validator str_len_range need params') 91 | let min = Math.max(0, params[0]) 92 | if (typeof val !== 'string' || val.length < min || val.length > params[1]) { 93 | validatorRet.push(params[2] || `请填写${min} ~ ${params[1]}`) 94 | } 95 | } 96 | /** 97 | * num_range:[min, max[, tips]] 98 | */ 99 | if (rule === 'num_range') { 100 | if (!params.length) throw new Error('validator num_range need params') 101 | if (typeof val !== 'number' || val.length < params[0] || val.length > params[1]) { 102 | validatorRet.push(params[2] || `请填写${params[0]} ~ ${params[1]}`) 103 | } 104 | } 105 | /** 106 | * phone:[type[, tips]] //type: mobile, tel . Default is both. 107 | */ 108 | if (rule === 'phone') { 109 | if (!params.length) throw new Error('validator phone need params') 110 | switch (params[0]) { 111 | case 'mobile': 112 | if (!REGEXP_MOBILE.test(val)) { 113 | validatorRet.push(params[1] || `请填写正确的手机号`) 114 | } 115 | break 116 | case 'tel': 117 | if (!REGEXP_TELEPHONE.test(val)) { 118 | validatorRet.push(params[1] || `请填写正确的电话号码,如025-88886699`) 119 | } 120 | break 121 | default : 122 | if (!REGEXP_TELEPHONE.test(val) && !REGEXP_MOBILE.test(val)) { 123 | validatorRet.push(params[1] || '请填写正确的手机号或电话号码,如025-88886699') 124 | } 125 | break 126 | } 127 | } 128 | /** 129 | * url:[[tips]] 130 | */ 131 | if (rule === 'url') { 132 | if (!/^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/.test(val)) { 133 | validatorRet.push(params[0] || `请填写正确的网址。`) 134 | } 135 | } 136 | /** 137 | * date:[{startDate:'',endDate:'',tips:''}] 138 | * date:{startDate:'',endDate:'',tips:''} 139 | * { 140 | title: '活动时间', 141 | type: 'startEndDate', 142 | isRange: true, 143 | items: [ 144 | { 145 | type: 'start', 146 | val: '', 147 | validator: {required: [true], ignore: this.isCheck}, 148 | key: 'actSttime' 149 | }, 150 | { 151 | type: 'end', 152 | val: '', 153 | validator: {required: [true], rules: {date: {startDate: this.mainData['actSttime']}}, ignore: this.isCheck}, 154 | key: 'actEdtime' 155 | } 156 | ] 157 | }, 158 | * { 159 | title: '执行时间', 160 | type: 'startEndDate', 161 | isRange: true, 162 | items: [ 163 | { 164 | type: 'start', 165 | val: '', 166 | validator: {required: [true], rules: {date: {startDate: this.mainData['actSttime'], endDate: this.mainData['actEdtime']}}, ignore: this.isCheck}, 167 | key: 'exeSttime' 168 | }, 169 | { 170 | type: 'end', 171 | val: '', 172 | validator: {required: [true], rules: {date: [{startDate: this.mainData['actSttime'], endDate: this.mainData['actEdtime']}, {startDate: this.mainData['exeSttime']}]}, ignore: this.isCheck}, 173 | key: 'exeEdtime' 174 | } 175 | ] 176 | } 177 | */ 178 | if (rule === 'date') { 179 | if (Array.isArray(params)) { 180 | for (let i = 0, il = params.length; i < il; i++) { 181 | let r = checkDate(params[i], val) 182 | if (r) validatorRet.push(r) 183 | } 184 | } else { 185 | let r = checkDate(params, val) 186 | if (r) validatorRet.push(r) 187 | } 188 | } 189 | /** 190 | * GB_32100-2015_法人和其他组织统一社会信用代码编码规则 191 | * { 192 | title: '统一社会信用代码', 193 | type: 'unifiedSocialCreditCode', 194 | validator: {required: [true], rules: {unifiedSocialCreditCode: ['请填写18位统一社会信用代码']}, ignore: this.isCheck}, 195 | key: 'creditCode', 196 | hide: !this.isCoop 197 | }, 198 | */ 199 | if (rule === 'unifiedSocialCreditCode') { 200 | // data = "91350100M000100Y43,91430382092581024J,914103057167119596,9A350100M000100Y47,91340828578527976Q,91350128M00000019A,52100000523000026F,91350200M000000510,91520421MA6DJ09246,91440300359143307G,91340881MA2MQ0T315" 201 | if (!REGEXP_USC.test(val)) { 202 | validatorRet.push(params[0] || '请填写正确的统一社会信用代码') 203 | } 204 | } 205 | 206 | /** 207 | * 自定义正则校验 208 | * validator: {required: [true], rules: {customRegexp: [/^\d$/, '请填写数字']}}, 209 | */ 210 | if (rule === 'customRegexp') { 211 | if (!params[0] || !params[1]) throw new Error('validator customRegexp need params') 212 | if (!new RegExp(params[0]).test(val)) { 213 | validatorRet.push(params[1]) 214 | } 215 | } 216 | } 217 | 218 | if (validatorRet.length) ret[item.key] = validatorRet 219 | return ret 220 | } 221 | 222 | const checkDate = (params, val) => { 223 | if (!params || (!params.startDate && !params.endDate)) throw new Error('validator date need params') 224 | let date = moment(val) 225 | if (params.startDate && params.endDate) { 226 | let startDate = moment(params.startDate) 227 | let endDate = moment(params.endDate) 228 | if (!date.isBetween(startDate, endDate, null, '[]')) { 229 | return (params.tips || `请选择${params.startDate} ~ ${params.endDate}之间日期。`) 230 | } 231 | } else if (params.endDate) { 232 | let endDate = moment(params.endDate) 233 | if (date.isAfter(endDate)) return (params.tips || `不能晚于 ${params.endDate}。`) 234 | } else if (params.startDate) { 235 | let startDate = moment(params.startDate) 236 | if (date.isBefore(startDate)) return (params.tips || `不能早于 ${params.startDate}。`) 237 | } 238 | } 239 | 240 | 241 | export const formatDate = (value,type) => { 242 | let format = '' 243 | switch (type) { 244 | case 'day': format = 'YYYY-MM-DD' 245 | break 246 | case 'second': format = 'YYYY-MM-DD HH:MM:SS' 247 | break 248 | default : format = type 249 | break 250 | } 251 | return moment(value).format(format) 252 | 253 | } 254 | export const fromNow = (value) => { 255 | return moment(value).fromNow(); 256 | } 257 | 258 | export const getQueryString = (name) => { 259 | var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'), 260 | r = window.location.search.substr(1).match(reg), 261 | context = ''; 262 | if (r != null) { 263 | context = r[2]; 264 | } 265 | reg = null; 266 | r = null; 267 | return context === null || context === '' || context === 'undefined' ? '' : context; 268 | } 269 | 270 | //手机号136****1221 271 | export const getFiterPhone = phone => { 272 | return phone.replace(/(\d{3})(?=\d{4})(?:\d{4})/, '$1****') 273 | } 274 | 275 | export const formatToParams = obj => { 276 | const arr = [] 277 | for (let key in obj) { 278 | if (!obj.hasOwnProperty(key)) { 279 | continue 280 | } 281 | arr.push(`${key}=${obj[key]}`) 282 | } 283 | return arr.join('&') 284 | } 285 | 286 | export const tofixed = value => { 287 | value = value.toString() 288 | return parseFloat(value.replace(/(\d+)\./,'$1')) / ( Math.pow(10, value.length + 1) / Math.pow(10, value.length - 1)) 289 | } 290 | 291 | export const cutNumber = value => { 292 | return value.toString().replace(/\B(?=(\d{3})+(?!(\d)))/g, ',') 293 | } -------------------------------------------------------------------------------- /src/pluges/service.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by root on 2017/7/12. 3 | */ 4 | import axios from 'axios' 5 | import Toast from '@/toast' 6 | let defaultConfig = { 7 | needLoading: true 8 | } 9 | axios.interceptors.request.use( 10 | config => { 11 | Object.assign(defaultConfig, config) 12 | let reg = new RegExp('.(a)') 13 | reg.test(defaultConfig.url) 14 | ? (defaultConfig.withCredentials = false) 15 | : (defaultConfig.withCredentials = true) 16 | defaultConfig.needLoading ? Toast.show() : Toast.hide() 17 | return defaultConfig 18 | }, 19 | error => { 20 | Toast.hide() 21 | return Promise.reject(error) 22 | } 23 | ) 24 | export default store => { 25 | axios.interceptors.response.use( 26 | response => { 27 | Toast.hide() 28 | if ( 29 | response.data.code == 0 || 30 | response.data.start == 0 || 31 | response.data.errorCode == 0 32 | ) { 33 | if (response.data.content) { 34 | return Promise.resolve(response.data.content) 35 | } else if (response.data.data) { 36 | return Promise.resolve(response.data.data) 37 | } 38 | } else if (response.data.result == 1001) { 39 | return Promise.resolve(response.data.data) 40 | } else if (response.data.result == -200) { 41 | // token expired 42 | // window.location.href = "?cmd=login"; 43 | return false 44 | } else { 45 | store.commit('API_FALID', { data: response.data.errorMsg }) 46 | return false 47 | } 48 | }, 49 | error => { 50 | Toast.hide() 51 | console.error('response error', error, error && error.response) 52 | store.commit('API_FALID', { data: '网络错误' }) 53 | return Promise.reject(error) 54 | } 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /src/pluges/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import createLogger from 'vuex/dist/logger' 4 | import common from '../common' 5 | 6 | Vue.use(Vuex) 7 | export default (data = {}) => { 8 | console.log(data) 9 | return new Vuex.Store( 10 | Object.assign({}, { 11 | strict: process.env.NODE_ENV !== 'production', 12 | ...common, 13 | modules: data 14 | }, process.env.NODE_ENV === 'production' ? {} : { 15 | plugins: [createLogger()] 16 | } 17 | ) 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/pluges/vuexMap.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapState, mapActions } from 'vuex' 2 | import { createDecorator } from 'vue-class-component' 3 | 4 | export const MapGetters = options => { 5 | if (options === void 0) { options = {} } 6 | return createDecorator((componentOptions) => { 7 | if (typeof componentOptions.computed !== 'object') { 8 | componentOptions.computed = Object.create(null) 9 | } 10 | componentOptions.computed = { ...mapGetters(options) } 11 | }) 12 | } 13 | 14 | export const MapStates = options => { 15 | if (options === void 0) { options = {} } 16 | return createDecorator((componentOptions) => { 17 | if (typeof componentOptions.computed !== 'object') { 18 | componentOptions.computed = Object.create(null) 19 | } 20 | componentOptions.computed = { ...mapState(options) } 21 | }) 22 | } 23 | 24 | export const MapActions = options => { 25 | if (options === void 0) { options = {} } 26 | return createDecorator((componentOptions) => { 27 | if (typeof componentOptions.methods !== 'object') { 28 | componentOptions.methods = Object.create(null) 29 | } 30 | componentOptions.methods = { ...mapActions(options) } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /view/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /view/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /view/test1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var webpack = require("webpack"); 3 | var fileReder = require("./readfiles"); 4 | var files = fileReder("./src/features"); 5 | var imgUrl = require("./bin/config/dev").default; 6 | var jsFile = {}; 7 | function resolve(dir) { 8 | return path.join(__dirname, "..", dir); 9 | } 10 | files.forEach(data => { 11 | jsFile[data] = [ 12 | "webpack-hot-middleware/client", 13 | "./src/features/" + data + "/main.js" 14 | ]; 15 | }); 16 | 17 | module.exports = { 18 | entry: jsFile, 19 | output: { 20 | path: path.resolve(__dirname, "./static"), 21 | publicPath: "/", 22 | filename: "[name].min.js" 23 | }, 24 | resolve: { 25 | modules: [path.join(__dirname, "./node_modules")], 26 | extensions: [".js", ".vue", ".json"], 27 | alias: { 28 | vue: "vue/dist//vue.esm.js", 29 | "@": path.join(__dirname, "src/components") 30 | } 31 | }, 32 | plugins: [ 33 | new webpack.optimize.OccurrenceOrderPlugin(), 34 | new webpack.HotModuleReplacementPlugin(), 35 | new webpack.NoEmitOnErrorsPlugin() 36 | ], 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.vue$/, 41 | loader: "vue-loader", 42 | options: { 43 | loaders: { 44 | scss: "style-loader!css-loader!sass-loader" 45 | }, 46 | postcss: [ 47 | require("autoprefixer")({ 48 | browsers: ["last 7 versions"] 49 | }) 50 | ] 51 | } 52 | }, 53 | { 54 | test: /\.css$/, 55 | loader: "style-loader!css-loader" 56 | }, 57 | { 58 | test: /\.scss$/, 59 | loader: "style-loader!css-loader!sass-loader" 60 | }, 61 | { 62 | test: /\.(js|vue)$/, 63 | loader: "eslint-loader", 64 | enforce: "pre", 65 | include: [path.resolve(__dirname, "src")], 66 | options: { 67 | // 这里的配置项参数将会被传递到 eslint 的 CLIEngine 68 | formatter: require("eslint-friendly-formatter") // 指定错误报告的格式规范 69 | } 70 | }, 71 | { 72 | test: /\.js$/, 73 | loader: "babel-loader", 74 | exclude: /node_modules/ 75 | }, 76 | { 77 | test: /\.json$/, 78 | loader: "json" 79 | }, 80 | { 81 | test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/, 82 | loader: "file-loader" 83 | }, 84 | { 85 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 86 | loader: "url-loader", 87 | options: { 88 | limit: 10000, 89 | name: path.posix.join(imgUrl.imageHost, "img/[name].[hash:7].[ext]") 90 | } 91 | } 92 | ] 93 | } 94 | }; 95 | -------------------------------------------------------------------------------- /webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var fs = require("fs"); 3 | var webpack = require("webpack"); 4 | var HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | var fileReder = require("./readfiles"); 6 | var files = fileReder("./src/features"); 7 | var jsFile = {}; 8 | jsFile["vender"] = ["vue", "vue-router", "vuex", "axios"]; 9 | 10 | files.forEach(data => { 11 | jsFile[data] = "./src/features/" + data + "/main.js"; 12 | }); 13 | var pluginsArray1 = connect(); 14 | 15 | var pluginsArray2 = [ 16 | new HtmlWebpackPluginDist(), 17 | new webpack.optimize.OccurrenceOrderPlugin(), 18 | new webpack.optimize.UglifyJsPlugin({ 19 | output: { 20 | comments: false 21 | }, 22 | compress: { 23 | warnings: false 24 | } 25 | }), 26 | //new webpack.optimize.CommonsChunkPlugin('common', 'dist/js/vendor.js'), 27 | new webpack.optimize.CommonsChunkPlugin({ 28 | name: ["vender"], 29 | minChunks: 1 30 | }), 31 | new webpack.NoErrorsPlugin() 32 | ]; 33 | pluginsArray1 = pluginsArray1.concat(pluginsArray2); 34 | 35 | module.exports = { 36 | entry: jsFile, 37 | output: { 38 | path: path.resolve(__dirname, "./dist"), 39 | publicPath: "/", 40 | filename: "[name].[chunkhash].js" 41 | }, 42 | resolve: { 43 | modules: [path.join(__dirname, "./node_modules")], 44 | extensions: [".js", ".vue", ".json"], 45 | alias: { 46 | vue: "vue/dist//vue.esm.js", 47 | "@": path.join(__dirname, "src/components") 48 | } 49 | }, 50 | plugins: pluginsArray1, 51 | module: { 52 | rules: [ 53 | { 54 | test: /\.vue$/, 55 | loader: "vue-loader", 56 | options: { 57 | loaders: { 58 | scss: "style-loader!css-loader!sass-loader" 59 | }, 60 | postcss: [ 61 | require("autoprefixer")({ 62 | browsers: ["last 7 versions"] 63 | }) 64 | ] 65 | } 66 | }, 67 | { 68 | test: /\.css$/, 69 | loader: "style-loader!css-loader" 70 | }, 71 | { 72 | test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/, 73 | loader: "file-loader" 74 | }, 75 | { 76 | test: /\.scss$/, 77 | loader: "style-loader!css-loader!sass-loader" 78 | }, 79 | { 80 | test: /\.js$/, 81 | loader: "babel-loader", 82 | exclude: /node_modules/ 83 | }, 84 | { 85 | test: /\.json$/, 86 | loader: "json" 87 | }, 88 | { 89 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 90 | loader: "url-loader", 91 | options: { 92 | limit: 10000, 93 | name: path.posix.join("/", "/img/[name].[hash:7].[ext]") 94 | } 95 | } 96 | ] 97 | } 98 | }; 99 | 100 | function connect() { 101 | var arr = []; 102 | files.forEach(function(data) { 103 | var cache = null; 104 | cache = new HtmlWebpackPlugin({ 105 | filename: path.resolve(__dirname, "./dist/" + data + ".html"), 106 | template: "./view/" + data + ".html", 107 | chunks: ["vender", data] 108 | }); 109 | arr.push(cache); 110 | }); 111 | return arr; 112 | } 113 | 114 | function HtmlWebpackPluginDist() {} 115 | HtmlWebpackPluginDist.prototype.apply = function(compiler) { 116 | var self = this; 117 | // Hook into the html-webpack-plugin processing 118 | compiler.plugin("compilation", function(compilation) { 119 | compilation.plugin("html-webpack-plugin-before-html-processing", function( 120 | data, 121 | cb 122 | ) { 123 | console.log(data.html); 124 | var filename = data.assets.js; 125 | filename = filename.map(function(data) { 126 | return data.replace(/\/js\//, ""); 127 | }); 128 | filename = filename.map(function(data) { 129 | var name = data.split("."); 130 | return name[0]; 131 | }); 132 | data.html = data.html.replace( 133 | '', 136 | "" 137 | ); 138 | cb(null, data); 139 | }); 140 | }); 141 | }; 142 | --------------------------------------------------------------------------------