├── .gitattributes
├── .eslintignore
├── generators
├── app
│ ├── templates
│ │ ├── static
│ │ │ └── .gitkeep
│ │ ├── src
│ │ │ ├── assets
│ │ │ │ ├── img
│ │ │ │ │ ├── .gitkeep
│ │ │ │ │ ├── alert-bg@2x.png
│ │ │ │ │ └── alert-bg@3x.png
│ │ │ │ ├── js
│ │ │ │ │ └── .gitkeep
│ │ │ │ ├── css
│ │ │ │ │ ├── vars.less
│ │ │ │ │ ├── reset.css
│ │ │ │ │ ├── common.css
│ │ │ │ │ ├── mixins.less
│ │ │ │ │ ├── animation.css
│ │ │ │ │ └── normalize.css
│ │ │ │ └── logo.png
│ │ │ ├── mixins
│ │ │ │ ├── .gitkeep
│ │ │ │ └── toggle.js
│ │ │ ├── store
│ │ │ │ ├── actions.js
│ │ │ │ ├── getters.js
│ │ │ │ ├── mutations.js
│ │ │ │ ├── types.js
│ │ │ │ ├── modules
│ │ │ │ │ └── list.js
│ │ │ │ └── index.js
│ │ │ ├── filters
│ │ │ │ ├── toHyphenate.js
│ │ │ │ └── toCameCase.js
│ │ │ ├── directions
│ │ │ │ └── focus.js
│ │ │ ├── skeleton.entry.js
│ │ │ ├── modules
│ │ │ │ └── index
│ │ │ │ │ ├── index.vue
│ │ │ │ │ ├── index.html
│ │ │ │ │ └── _index.js
│ │ │ ├── eventBus
│ │ │ │ └── index.js
│ │ │ ├── config
│ │ │ │ ├── apis.js
│ │ │ │ ├── env.js
│ │ │ │ └── axiosConfig.js
│ │ │ ├── router
│ │ │ │ └── index.js
│ │ │ ├── components
│ │ │ │ ├── global.js
│ │ │ │ ├── skeleton.vue
│ │ │ │ ├── Toast.vue
│ │ │ │ ├── textCarousel.vue
│ │ │ │ ├── vwDemo.vue
│ │ │ │ ├── Loading.vue
│ │ │ │ ├── Alert.vue
│ │ │ │ └── Confirm.vue
│ │ │ ├── utils
│ │ │ │ ├── types.js
│ │ │ │ ├── storage.js
│ │ │ │ └── utils.js
│ │ │ ├── plugins
│ │ │ │ ├── confirm
│ │ │ │ │ └── index.js
│ │ │ │ ├── loading
│ │ │ │ │ └── index.js
│ │ │ │ ├── alert
│ │ │ │ │ └── index.js
│ │ │ │ └── toast
│ │ │ │ │ └── index.js
│ │ │ ├── _main.js
│ │ │ ├── pages
│ │ │ │ └── _HelloWorld.vue
│ │ │ └── App.vue
│ │ ├── .eslintignore
│ │ ├── config
│ │ │ ├── test.env.js
│ │ │ ├── prod.env.js
│ │ │ ├── dll.libs.dependencies.js
│ │ │ ├── dev.env.js
│ │ │ └── _index.js
│ │ ├── build
│ │ │ ├── logo.png
│ │ │ ├── ommit-css-webpack-plugin.js
│ │ │ ├── vue-loader.conf.js
│ │ │ ├── webpack.skeleton.conf.js
│ │ │ ├── build.js
│ │ │ ├── check-versions.js
│ │ │ ├── webpack.dll.conf.js
│ │ │ ├── _utils.js
│ │ │ ├── _webpack.dev.conf.js
│ │ │ ├── _webpack.test.conf.js
│ │ │ ├── _webpack.base.conf.js
│ │ │ └── _webpack.prod.conf.js
│ │ ├── .editorconfig
│ │ ├── _gitignore
│ │ ├── .babelrc
│ │ ├── skeleton.js
│ │ ├── jsdoc.conf.json
│ │ ├── _index.html
│ │ ├── .eslintrc.js
│ │ ├── _postcssrc.js
│ │ ├── CHANGELOG.md
│ │ ├── _package.json
│ │ ├── README.md
│ │ └── dist
│ │ │ └── skeleton.json
│ └── index.js
├── mpage
│ ├── templates
│ │ └── src
│ │ │ └── modules
│ │ │ └── index
│ │ │ ├── _index.vue
│ │ │ ├── _index.html
│ │ │ └── _index.js
│ └── index.js
├── page
│ ├── templates
│ │ └── src
│ │ │ ├── pages
│ │ │ └── demo.vue
│ │ │ └── router
│ │ │ └── index.js
│ └── index.js
├── publicPath
│ ├── index.js
│ └── templates
│ │ └── config
│ │ └── index.js
└── imagePublicPath
│ ├── index.js
│ └── templates
│ └── config
│ └── index.js
├── screenshots
├── a.gif
├── a2.gif
├── a3.gif
├── a4.gif
└── a5.gif
├── .travis.yml
├── .editorconfig
├── .yo-rc.json
├── .gitignore
├── __tests__
└── app.js
├── LICENSE
├── package.json
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | **/templates
3 |
--------------------------------------------------------------------------------
/generators/app/templates/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/img/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/js/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/mixins/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/actions.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/getters.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/mutations.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/types.js:
--------------------------------------------------------------------------------
1 | export const SET_INFO = 'SET_INFO'
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/vars.less:
--------------------------------------------------------------------------------
1 | @white: #fff;
2 | @gray: #666;
3 |
4 |
--------------------------------------------------------------------------------
/screenshots/a.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/screenshots/a.gif
--------------------------------------------------------------------------------
/generators/app/templates/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | node_modules/*
3 | /config/
4 | /dist/
5 | /*.js
6 |
--------------------------------------------------------------------------------
/screenshots/a2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/screenshots/a2.gif
--------------------------------------------------------------------------------
/screenshots/a3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/screenshots/a3.gif
--------------------------------------------------------------------------------
/screenshots/a4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/screenshots/a4.gif
--------------------------------------------------------------------------------
/screenshots/a5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/screenshots/a5.gif
--------------------------------------------------------------------------------
/generators/app/templates/config/test.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"test"'
4 | }
5 |
--------------------------------------------------------------------------------
/generators/app/templates/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/generators/app/templates/src/filters/toHyphenate.js:
--------------------------------------------------------------------------------
1 | export const hyphenate = val => val.replace(/([A-Z])/g, "-$1").toLowerCase()
2 |
--------------------------------------------------------------------------------
/generators/app/templates/build/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/generators/app/templates/build/logo.png
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/generators/app/templates/src/assets/logo.png
--------------------------------------------------------------------------------
/generators/app/templates/src/directions/focus.js:
--------------------------------------------------------------------------------
1 | export const focus = {
2 | inserted: function(el) {
3 | el.focus();
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - v11
4 | - v10
5 | - v8
6 | - v6
7 | - v4
8 | after_script: cat ./coverage/lcov.info | coveralls
9 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/img/alert-bg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/generators/app/templates/src/assets/img/alert-bg@2x.png
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/img/alert-bg@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/501981732/generator-easy-vue/HEAD/generators/app/templates/src/assets/img/alert-bg@3x.png
--------------------------------------------------------------------------------
/generators/app/templates/config/dll.libs.dependencies.js:
--------------------------------------------------------------------------------
1 | // 工程组件,用于提前编译 dll目录
2 | const lib = {
3 | dll_vendor: ['vue/dist/vue.esm.js', 'vue-router']
4 |
5 | }
6 |
7 | module.exports = lib;
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-node": {
3 | "promptValues": {
4 | "authorName": "wangmeng",
5 | "authorEmail": "501981732@qq.com",
6 | "authorUrl": "https://github.com/501981732"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/generators/app/templates/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/generators/app/templates/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/generators/app/templates/_gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/generators/app/templates/src/mixins/toggle.js:
--------------------------------------------------------------------------------
1 | export const toggle = {
2 | data() {
3 | return {
4 | show: false
5 | }
6 | },
7 | methods: {
8 | toggleShow() {
9 | this.show = !this.show
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/generators/app/templates/src/skeleton.entry.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import skeleton from './components/skeleton.vue'
3 |
4 | console.log('Skeleton...')
5 |
6 | export default new Vue({
7 | components: {
8 | skeleton
9 | },
10 | template: ''
11 | })
12 |
--------------------------------------------------------------------------------
/generators/app/templates/src/modules/index/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | hello index
10 |
11 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/generators/mpage/templates/src/modules/index/_index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 | hello index
10 |
11 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/generators/app/templates/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | },
8 | "useBuiltIns": true,
9 | }],
10 | "stage-2"
11 | ],
12 | "plugins": ["transform-vue-jsx", "transform-runtime"]
13 | }
14 |
--------------------------------------------------------------------------------
/generators/page/templates/src/pages/demo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
hello <%= page%>
4 |
5 |
6 |
7 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/generators/app/templates/src/eventBus/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | const EventBus = new Vue();
3 | /**
4 | * 事件总线
5 | * @example
6 | * this.$bus.$emit("someEvent", someData)
7 | * this.$bus.$on("someEvent", (v) => {console.log(v)})
8 | *
9 | */
10 | Object.defineProperties(Vue.prototype, {
11 | $bus: {
12 | get: function () {
13 | return EventBus
14 | }
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/__tests__/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const path = require('path');
3 | const assert = require('yeoman-assert');
4 | const helpers = require('yeoman-test');
5 |
6 | describe('generator-easy-vue:app', () => {
7 | beforeAll(() => {
8 | return helpers
9 | .run(path.join(__dirname, '../generators/app'))
10 | .withPrompts({ someAnswer: true });
11 | });
12 |
13 | it('creates files', () => {
14 | assert.file(['dummyfile.txt']);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/modules/list.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 分模块处理vuex
3 | */
4 | import * as types from '../types'
5 |
6 | const state = {
7 | info: {}
8 | }
9 |
10 | const actions = {
11 |
12 | }
13 |
14 | const getters = {
15 | info: state => state.info,
16 | }
17 |
18 | const mutations = {
19 | [types.SET_INFO](state, payload) {
20 | state.info = payload
21 | },
22 | }
23 |
24 | export default {
25 | state,
26 | actions,
27 | getters,
28 | mutations
29 | }
30 |
--------------------------------------------------------------------------------
/generators/app/templates/src/filters/toCameCase.js:
--------------------------------------------------------------------------------
1 | export const cameCase = val => {
2 | let reg = /-(\w)/g;
3 | return reg.replace(o, function(a, b) {
4 | // b为子项;
5 | return b.toUpperCase()
6 | })
7 | }
8 |
9 | export const caseCase2 = val => {
10 |
11 | let arr = str.split("-");
12 | for (let i = 1, len = arr.length; i < len; i++) {
13 | arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substring(1)
14 | }
15 | return arr.join('')
16 | }
17 |
--------------------------------------------------------------------------------
/generators/app/templates/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import list from './modules/list'
4 | import createLogger from 'vuex/dist/logger'
5 | import * as actions from './actions.js'
6 | import * as mutations from './mutations.js'
7 |
8 | Vue.use(Vuex)
9 |
10 | const debug = process.env.NODE_ENV !== 'production'
11 |
12 | export default new Vuex.Store({
13 | modules: {
14 | list,
15 | },
16 | actions,
17 | mutations,
18 | strict: debug,
19 | plugins: debug ? [createLogger()] : []
20 | })
--------------------------------------------------------------------------------
/generators/app/templates/build/ommit-css-webpack-plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = class OmmitCSSPlugin {
2 | constructor() {}
3 |
4 | apply(compiler) {
5 | compiler.plugin('compilation', (compilation) => {
6 | compilation.plugin(
7 | 'html-webpack-plugin-alter-asset-tags',
8 | (args, cb) => {
9 | args.head = args.head.filter((link) => link.attributes.rel !== 'stylesheet');
10 | cb(null, args);
11 | }
12 | );
13 | });
14 | }
15 | }
--------------------------------------------------------------------------------
/generators/app/templates/src/config/apis.js:
--------------------------------------------------------------------------------
1 | import ax from './axiosConfig.js'
2 |
3 | let url = {},
4 | postUrls = {};
5 |
6 | if (process.env.NODE_ENV === "development") {
7 | url = {
8 | filter: "",
9 | };
10 | } else if (process.env.NODE_ENV === "test") {
11 | url = {
12 | filter: "",
13 | };
14 | } else if (process.env.NODE_ENV === "production") {
15 | url = {
16 | filter: "",
17 | };
18 | }
19 |
20 | const filter = (data) => ax.get(url.filter,{params:data})
21 |
22 | export default {
23 | filter,
24 | }
25 |
--------------------------------------------------------------------------------
/generators/mpage/templates/src/modules/index/_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= projectName %><% if(dns) {%>
8 |
9 | <% for(var i of dns.split(',')){ %><% }%><%}%>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/generators/app/templates/skeleton.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const htmlMinifier = require('html-minifier')
3 | const { resolve } = require('path')
4 |
5 | const createBundleRenderer = require('vue-server-renderer').createBundleRenderer
6 |
7 | const renderer = createBundleRenderer(resolve(__dirname, './dist/skeleton.json'), {
8 | template: fs.readFileSync(resolve(__dirname, './index.html'), 'utf-8')
9 | })
10 |
11 | renderer.renderToString({}, (err, html) => {
12 | html = htmlMinifier.minify(html, {
13 | collapseWhitespace: true,
14 | minifyCSS: true
15 | })
16 | fs.writeFileSync('index.html', html, 'utf-8')
17 | })
--------------------------------------------------------------------------------
/generators/page/templates/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import { routerBaseUrl } from '@/config/env.js'
4 | import HelloWorld from '@/pages/HelloWorld'
5 | // const HelloWorld = () => import('@/pages/HelloWorld')
6 |
7 | const <%= page%> = () => import('@/pages/<%= page%>')
8 |
9 | Vue.use(Router)
10 |
11 | export default new Router({
12 | mode: "hash",
13 | base: routerBaseUrl,
14 | routes: [
15 | {
16 | path: '/',
17 | name: 'HelloWorld',
18 | component: HelloWorld
19 | },{
20 | path: '/<%= page%>',
21 | name: '<%= page%>',
22 | component: <%= page%>
23 | }
24 | ]
25 | })
26 |
--------------------------------------------------------------------------------
/generators/app/templates/src/config/env.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 配置线上环境和线下环境切换
3 | * baseUrl 域名地址
4 | * routerBaseUrl 若开启history模式则线上补全路径
5 | * @example url='//zp.58.com/yy/2018/employerbrandselection/main' baseUrl='//zp.58.com' routerBaseUrl='/yy/2018/employerbrandselection/main'
6 | *
7 | */
8 |
9 | let baseUrl = "";
10 | let routerBaseUrl = "";
11 | if (process.env.NODE_ENV == "development") {
12 | // baseUrl = ''
13 | } else if (process.env.NODE_ENV == "test") {
14 | // 测试环境->代理proxy
15 | // baseUrl = "";
16 | // routerBaseUrl = "";
17 | } else if (process.env.NODE_ENV == "production") {
18 | baseUrl = "";
19 | routerBaseUrl = "";
20 | }
21 | export { baseUrl, routerBaseUrl };
22 |
--------------------------------------------------------------------------------
/generators/app/templates/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | // extract: true
14 | }),
15 | cssSourceMap: sourceMapEnabled,
16 | cacheBusting: config.dev.cacheBusting,
17 | transformToRequire: {
18 | video: ['src', 'poster'],
19 | source: 'src',
20 | img: 'src',
21 | image: 'xlink:href'
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/generators/app/templates/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import { routerBaseUrl } from '@/config/env.js'
4 | import HelloWorld from '@/pages/HelloWorld'
5 | // chunkname
6 | // const index = () => import( /* webpackChunkName: "index" */ '@/pages/index')
7 |
8 | Vue.use(Router)
9 |
10 | export default new Router({
11 | mode: "hash",
12 | base: routerBaseUrl,
13 | scrollBehavior(to, from, savedPosition) {
14 | if (savedPosition) {
15 | return savedPosition
16 | } else {
17 | return { x: 0, y: 0 }
18 | }
19 | },
20 | routes: [{
21 | path: '/',
22 | name: 'HelloWorld',
23 | component: HelloWorld,
24 | meta: {
25 | zIndex: 1
26 | }
27 | }]
28 | })
29 |
--------------------------------------------------------------------------------
/generators/mpage/templates/src/modules/index/_index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import <%=mpage%> from './<%=mpage%>.vue'
3 | import router from '@/router'
4 | import axios from 'axios'
5 | // import store from '@/store/'
6 | // import FastClick from 'fastclick'
7 |
8 | Vue.config.productionTip = false
9 |
10 | import 'babel-polyfill' // API垫片
11 |
12 | // import '@/assets/css/reset.css'
13 | // import '@/assets/css/normalize.css'
14 |
15 | // import 'amfe-flexible/index.js'
16 | // FastClick.attach(document.body);
17 |
18 | // vue插件
19 | import AlertPlugin from '@/plugins/alert/index.js'
20 | Vue.use(AlertPlugin)
21 |
22 | // 自动注入components
23 | import '@/components/global.js'
24 |
25 | window.axios = axios
26 |
27 | /* eslint-disable no-new */
28 | new Vue({
29 | el: '#app',
30 | components: { <%=mpage%> },
31 | template: '<<%=mpage%>/>'
32 | })
33 |
34 |
--------------------------------------------------------------------------------
/generators/publicPath/index.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const yosay = require('yosay');
3 | const Generator = require('yeoman-generator');
4 |
5 | module.exports = class extends Generator {
6 | // The name `constructor` is important here
7 | constructor(args, opts) {
8 | // Calling the super constructor is important so our generator is correctly set up
9 | super(args, opts);
10 | }
11 | initializing() {
12 | this.argument('publicPath', { type: String, required: true });
13 | }
14 | prompting() {}
15 |
16 | writing() {
17 | this.fs.copyTpl(
18 | this.templatePath('config/index.js'),
19 | this.destinationPath('config/index.js'),
20 | { publicPath: this.options.publicPath }
21 | );
22 | }
23 | install() {}
24 |
25 | end() {
26 | this.log(yosay(`Now the ${chalk.green(this.options.publicPath)} is ready!`))
27 | }
28 | };
--------------------------------------------------------------------------------
/generators/app/templates/src/components/global.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * 自动注入组件
4 | * require.context()
5 | * useage: import './components/global.js'
6 | * 引入组件时不再需要 import xx from 'xx' components:{xx}
7 | */
8 |
9 | import Vue from 'vue'
10 |
11 | function capitalizeFirstLetter(string) {
12 | return string.charAt(0).toUpperCase() + string.slice(1)
13 | }
14 |
15 | const requireComponent = require.context(
16 | '.', true, /.vue$/
17 | //找到components文件夹下以.vue命名的文件
18 |
19 | )
20 |
21 | requireComponent.keys().forEach(fileName => {
22 | const componentConfig = requireComponent(fileName)
23 | const componentName = capitalizeFirstLetter(
24 | fileName.replace( /(.*)(\/)/, '').replace(/.\w+$/, '')
25 | //因为得到的filename格式是: './xxx.vue' './xxx/xxx.vue', 所以这里我们去掉头和尾,只保留真正的文件名
26 | )
27 |
28 | Vue.component(componentName, componentConfig.default || componentConfig)
29 |
30 | })
--------------------------------------------------------------------------------
/generators/imagePublicPath/index.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const yosay = require('yosay');
3 | const Generator = require('yeoman-generator');
4 |
5 | module.exports = class extends Generator {
6 | // The name `constructor` is important here
7 | constructor(args, opts) {
8 | // Calling the super constructor is important so our generator is correctly set up
9 | super(args, opts);
10 | }
11 | initializing() {
12 | this.argument('imagePublicPath', { type: String, required: true });
13 | }
14 | prompting() {}
15 |
16 | writing() {
17 | this.fs.copyTpl(
18 | this.templatePath('config/index.js'),
19 | this.destinationPath('config/index.js'),
20 | { imagePublicPath: this.options.imagePublicPath }
21 | );
22 | }
23 | install() {}
24 |
25 | end() {
26 | this.log(yosay(`Now the ${chalk.green(this.options.imagePublicPath)} is ready!`))
27 | }
28 | };
--------------------------------------------------------------------------------
/generators/app/templates/jsdoc.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": {
3 | "allowUnknownTags": true
4 | },
5 | "source": {
6 | "include": ["./src/"],
7 | "exclude": [],
8 | "includePattern": "\\.(vue|js)$",
9 | "excludePattern": "(^|\\/|\\\\)_"
10 | },
11 | "plugins": [
12 | "node_modules/jsdoc-vue"
13 | // "plugins/markdown",
14 | // "plugins/summarize"
15 | ],
16 | "markdown": {
17 |
18 | },
19 | "templates": {
20 | "cleverLinks": false,
21 | "monospaceLinks": false,
22 | "default": {
23 | "outputSourceFiles": true
24 | }
25 | },
26 | "opts": {
27 | "template": "templates/default",
28 | "encoding": "utf8",
29 | "destination": "./jsdoc/",
30 | "recurse": true,
31 | "package": "./package.json",
32 | "reademe": "./READEME.md"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/generators/app/templates/_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | <%= projectName %><% if(dns) {%>
11 |
12 | <% for(var i of dns.split(',')){ %><% }%><%}%><% if(dns) {%>
13 | <% for(var i of dns.split(',')){ %><% }%><%}%>
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/generators/app/templates/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | // 'standard' // 如果想用官方推荐的standard
17 | ],
18 | // required to lint *.vue files
19 | plugins: [
20 | 'vue'
21 | ],
22 | // add your custom rules here
23 | rules: {
24 | // allow async-await
25 | 'generator-star-spacing': 'off',
26 | // allow debugger during development
27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/generators/app/templates/src/modules/index/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= projectName %><% if(dns) {%>
8 |
9 | <% for(var i of dns.split(',')){ %><% }%><%}%><% if(dns) {%>
10 | <% for(var i of dns.split(',')){ %><% }%><%}%>
11 |
12 |
13 |
14 |
15 |
16 |
17 | <% if(layout === 'vw'){ %>
18 |
19 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/generators/page/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const chalk = require('chalk');
3 | const yosay = require('yosay');
4 | const Generator = require('yeoman-generator');
5 |
6 | module.exports = class extends Generator {
7 | // The name `constructor` is important here
8 | constructor(args, opts) {
9 | // Calling the super constructor is important so our generator is correctly set up
10 | super(args, opts);
11 | }
12 | initializing() {
13 | this.argument('page', { type: String, required: true });
14 | }
15 | prompting() {}
16 |
17 | writing() {
18 | this.fs.copyTpl(
19 | this.templatePath('src/pages/demo.vue'),
20 | this.destinationPath('src/pages/' + this.options.page + '.vue'),
21 | { page: this.options.page }
22 | );
23 | this.fs.copyTpl(
24 | this.templatePath('src/router/index.js'),
25 | this.destinationPath('src/router/index.js'),
26 | { page: this.options.page }
27 | );
28 | }
29 | install() {}
30 |
31 | end() {
32 | this.log(yosay(`Now the page ${chalk.green(this.options.page)} is ready!`))
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/generators/app/templates/src/modules/index/_index.js:
--------------------------------------------------------------------------------
1 |
2 | import Vue from 'vue'
3 | import Index from './index.vue'
4 | import axios from 'axios'
5 | <% if(vuex) {%>
6 | import store from '@/store/'
7 | <% }%><% if(layout === 'rem' || layout === 'vw') {%>
8 | import FastClick from 'fastclick'
9 | <% }%>
10 |
11 | Vue.config.productionTip = false
12 |
13 | import 'babel-polyfill' // API垫片
14 |
15 | <% if(reset === 'reset.css') {%>
16 | import '@/assets/css/reset.css'
17 | <% } else if (reset === 'normalize.css') {%>
18 | import '@/assets/css/normalize.css'
19 | <% }%>
20 | <% if(layout === 'rem') {%>
21 | // REM布局方案 OR vw布局
22 | import 'amfe-flexible/index.js'
23 | FastClick.attach(document.body);
24 | <% } else if (layout === 'vw') {%>
25 | FastClick.attach(document.body);
26 | <% }%>
27 | // vue插件
28 | import AlertPlugin from '@/plugins/alert/index.js'
29 | Vue.use(AlertPlugin)
30 |
31 | // 自动注入components
32 | import '@/components/global.js'
33 |
34 | window.axios = axios
35 |
36 | /* eslint-disable no-new */
37 | new Vue({
38 | el: '#app',<% if(vuex) {%>
39 | store,<% }%>
40 | components: { Index },
41 | template: ''
42 | })
43 |
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 wangmeng <501981732@qq.com> (https://github.com/501981732)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/generators/app/templates/src/config/axiosConfig.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import vue from 'vue'
3 | import { baseUrl } from './env.js'
4 | import qs from 'qs'
5 | import Toast from '@/plugins/toast/index.js'
6 | import Loading from '@/plugins/loading/index.js'
7 | vue.use(Toast)
8 | vue.use(Loading)
9 |
10 | const ax = axios.create({
11 | baseURL: baseUrl,
12 | timeout: 10000,
13 | withCredentials: true // 允许携带cookie
14 | })
15 |
16 | // 添加请求拦截器
17 | ax.interceptors.request.use(function(config) {
18 | if (config.method === 'post') {
19 | config.data = qs.stringify(config.data);
20 | }
21 | return config;
22 | }, function(error) {
23 | return Promise.reject(error);
24 | });
25 |
26 | // 添加响应拦截器
27 | ax.interceptors.response.use(function(response) {
28 | if (process.env.NODE_ENV == 'development') {
29 | console.log(response)
30 | }
31 | return response;
32 | }, function(error) {
33 | if (error.message.includes('timeout')) { // 判断请求异常信息中是否含有超时timeout字符串
34 | console.log("错误回调", error)
35 | vue.$x.loading.hide()
36 | vue.$x.toast('请求超时请稍后再试')
37 | return Promise.reject(error); // reject这个错误信息
38 | }
39 | });
40 | export default ax
41 |
--------------------------------------------------------------------------------
/generators/app/templates/src/utils/types.js:
--------------------------------------------------------------------------------
1 | export const isArray = val => !!val && Array.isArray(val);
2 |
3 | export const isBoolean = val => typeof val === "boolean";
4 |
5 | export const isFunction = val => val && typeof val === "function";
6 |
7 | export const isNumber = val => typeof val === "number";
8 |
9 | export const isString = val => typeof val === "string";
10 |
11 | export const isSymbol = val => typeof val === "symbol";
12 |
13 | export const inBrowser = typeof window !== "undefined";
14 |
15 | export const UA = inBrowser && window.navigator.userAgent.toLowerCase();
16 |
17 | export const isIE = UA && /msie|trident/.test(UA);
18 |
19 | export const isIE9 = UA && UA.indexOf("msie 9.0") > 0;
20 |
21 | export const isEdge = UA && UA.indexOf("edge/") > 0;
22 |
23 | export const isAndroid = UA && UA.indexOf("android") > 0;
24 |
25 | export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA);
26 |
27 | export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
28 |
29 | export const isPhantomJS = UA && /phantomjs/.test(UA);
30 |
31 | export const isInAPP = UA && /wuba/.test(UA);
32 |
33 | export const isWeiXin = UA && /micromessenger/.test(UA);
34 |
35 | export const is360zhushou = UA && /360appstore/.test(UA);
36 |
--------------------------------------------------------------------------------
/generators/app/templates/build/webpack.skeleton.conf.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const nodeExternals = require('webpack-node-externals')
4 | const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
5 | // const VueLoaderPlugin = require('vue-loader/lib/plugin')
6 |
7 | module.exports = {
8 | target: 'node',
9 | entry: {
10 | skeleton: './src/skeleton.entry.js'
11 | },
12 | output: {
13 | path: path.resolve(__dirname, '../dist'),
14 | publicPath: '/dist/',
15 | filename: '[name].js',
16 | libraryTarget: 'commonjs2'
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.css$/,
22 | use: [
23 | 'vue-style-loader',
24 | 'css-loader'
25 | ]
26 | },
27 | {
28 | test: /\.vue$/,
29 | loader: 'vue-loader'
30 | }
31 | ]
32 | },
33 | externals: nodeExternals({
34 | whitelist: /\.css$/
35 | }),
36 | resolve: {
37 | alias: {
38 | 'vue$': 'vue/dist/vue.esm.js'
39 | },
40 | extensions: ['*', '.js', '.vue', '.json']
41 | },
42 | plugins: [
43 | // new VueLoaderPlugin(),
44 | new VueSSRServerPlugin({
45 | filename: 'skeleton.json'
46 | })
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/generators/app/templates/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/skeleton.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
64 |
--------------------------------------------------------------------------------
/generators/app/templates/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/generators/mpage/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const chalk = require('chalk');
3 | const yosay = require('yosay');
4 | const Generator = require('yeoman-generator');
5 |
6 | module.exports = class extends Generator {
7 | // The name `constructor` is important here
8 | constructor(args, opts) {
9 | // Calling the super constructor is important so our generator is correctly set up
10 | super(args, opts);
11 | }
12 | initializing() {
13 | this.argument('mpage', {
14 | type: String,
15 | required: true
16 | });
17 | }
18 | prompting() {}
19 |
20 | writing() {
21 | let list = [
22 | ['src/modules/index/_index.js', `src/modules/${this.options.mpage}/${this.options.mpage}.js`],
23 | ['src/modules/index/_index.vue', `src/modules/${this.options.mpage}/${this.options.mpage}.vue`],
24 | ['src/modules/index/_index.html', `src/modules/${this.options.mpage}/${this.options.mpage}.html`],
25 | ]
26 | list.forEach(item => {
27 | let fromFile = item[0];
28 | let toFile = item[1];
29 | this.fs.copyTpl(
30 | this.templatePath(fromFile),
31 | this.destinationPath(toFile),
32 | // 将配置参数带过去
33 | {
34 | mpage: this.options.mpage
35 | }
36 | );
37 | })
38 | }
39 | install() {}
40 |
41 | end() {
42 | this.log(yosay(`Now the ${chalk.green('mutil page')} is ready!`))
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/generators/app/templates/_postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 | <%if(layout === 'rem') {%>
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | // css后处理器
9 | "autoprefixer": {}
10 | },
11 | // rem自动转换插件
12 | // 若想排除第三方库可以用基于postcss-px2rem 的postcss-px2rem-exclude or px2rem-exclude
13 | "postcss-pxtorem": {
14 | rootValue: 75,
15 | unitPrecision: 5,
16 | propList: ['*'],
17 | selectorBlackList: [],
18 | replace: true,
19 | mediaQuery: false,
20 | minPixelValue: 12
21 | }
22 | }
23 | <% }%><%if(layout === 'vw') {%>
24 | module.exports = {
25 | "plugins": {
26 | "postcss-import": {},
27 | "postcss-url": {},
28 | "postcss-aspect-ratio-mini": {}, // 处理元素容器宽高比
29 | "postcss-write-svg": {
30 | utf8: false
31 | },
32 | "postcss-preset-env": {
33 | stage: 2,
34 | },
35 | "postcss-px-to-viewport": {
36 | viewportWidth: 750, //视窗的宽度,对应的是我们设计稿的宽度,一般是750
37 | viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
38 | unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
39 | viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw
40 | selectorBlackList: ['.ignore', '.hairlines'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
41 | minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
42 | mediaQuery: false, // 允许在媒体查询中转换`px`
43 | exclude:/node_modules/i, //排除第三方库
44 | // selectorBlackList: ['delivery_alert_box']//黑名单
45 | },
46 | // "cssnano": { //压缩和清理CSS代码 cssnano和css-loader捆绑在一起,所以不需要自己加载它
47 | // preset: "advanced",
48 | // autoprefixer: false,
49 | // "postcss-zindex": false
50 | // },
51 | }
52 | }
53 | <% }%>
54 |
--------------------------------------------------------------------------------
/generators/app/templates/src/plugins/confirm/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Confirm 插件
3 | * @example
4 | * this.$x.confirm({
5 | * title:'提示1',
6 | * body: '1',
7 | * cancleText: '取消',
8 | * confirmText: '确定',
9 | * btnReverse: false, //按钮是否反正
10 | * useHTMLString: 'false' //是否使用动态HTML插入
11 | * }).then(res => {
12 | * console.log(res) //根据res判断是取消还是确定
13 | * })
14 | */
15 | import Vue from 'vue'
16 | import Confirm from '@/components/Confirm.vue'
17 |
18 | const defaultProps = {
19 |
20 | }
21 |
22 | const plugin = {
23 | install(vue, props = {}) {
24 | const ConfirmPlugin = vue.extend(Confirm)
25 | let $vm = new ConfirmPlugin({
26 | el: document.createElement('div')
27 | })
28 | document.body.appendChild($vm.$el)
29 |
30 | function confirm(options) {
31 | if ($vm.show) return
32 |
33 | if (typeof options === 'string') {
34 | options = {
35 | body: arguments[0]
36 | }
37 | }
38 |
39 | $vm = Object.assign($vm, defaultProps, props, options)
40 |
41 | $vm.show = true
42 |
43 | return new Promise((resolve, reject) => {
44 | $vm.$on('confirm',_ => {
45 | resolve(true)
46 | })
47 |
48 | $vm.$on('cancle', _ => {
49 | resolve(false)
50 | })
51 |
52 | })
53 | }
54 |
55 | if( !vue.$x) {
56 | vue.$x = {
57 | confirm
58 | }
59 | } else {
60 | vue.$x.confirm = confirm
61 | }
62 | vue.mixin({
63 | created: _ => {
64 | this.$x = vue.$x
65 | }
66 | })
67 | }
68 | }
69 | export default plugin
70 |
--------------------------------------------------------------------------------
/generators/app/templates/src/_main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 | <% if(vuex) {%>
7 | import store from '@/store/'
8 | <% }%><% if(layout === 'rem' || layout === 'vw') {%>
9 | import FastClick from 'fastclick'
10 | <% }%>
11 |
12 | import api from "@/config/apis.js";
13 |
14 | Vue.config.productionTip = false
15 |
16 | import 'babel-polyfill' // API垫片
17 |
18 | <% if(reset === 'reset.css') {%>
19 | import './assets/css/reset.css'
20 | <% } else if (reset === 'normalize.css') {%>
21 | import './assets/css/normalize.css'
22 | <% }%>
23 | import "./assets/css/animation.css";
24 | import "./assets/css/common.css";
25 |
26 | <% if(layout === 'rem') {%>
27 | // REM布局方案 OR vw布局
28 | import 'amfe-flexible/index.js'
29 | FastClick.attach(document.body);
30 | <% } else if (layout === 'vw') {%>
31 | FastClick.attach(document.body);
32 | <% }%>
33 | // 时间总线
34 | import '@/eventBus/index.js'
35 | /* eslint-disable no-unused-vars */
36 | // import vConsole from "vconsole";
37 | // const insvConsole = new vConsole();
38 |
39 | // 自动注入components
40 | import './components/global.js'
41 |
42 | // vue插件
43 | import AlertPlugin from "./plugins/alert/index.js";
44 | import ToastPlugin from "./plugins/toast/index.js";
45 | import ConformPlugin from "./plugins/confirm/index.js";
46 | import LoadingPlugin from "./plugins/loading/index.js";
47 |
48 | Vue.use(AlertPlugin);
49 | Vue.use(ToastPlugin);
50 | Vue.use(ConformPlugin);
51 | Vue.use(LoadingPlugin);
52 | // mount api
53 | Vue.prototype.$api = api;
54 |
55 |
56 | /* eslint-disable no-new */
57 | new Vue({
58 | el: '#app',
59 | router,<% if(vuex) {%>
60 | store,<% }%>
61 | components: { App },
62 | template: ''
63 | })
64 |
65 |
--------------------------------------------------------------------------------
/generators/app/templates/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Changelog
2 |
3 | #### todo
4 |
5 | - 非常棒的preload prefetch and prepack 相关插件不支持webpack3.X
6 |
7 | #### 0.4.0
8 |
9 | - 净化css,css tree shake, config/index配置purgecssPath
10 | - postcss插件替换 postcss-preset-env替代cssnext 默认stage:2
11 |
12 | #### 0.3.9
13 |
14 | - 路由动画
15 |
16 | #### 0.3.3
17 |
18 | - 增加测试环境:开发环境接口 -> **mock**,测试环境走 ->**proxy**,生产环境直接打包线上全路径
19 | - 增加eventBus事件总线,挂载vue 全局调用
20 | - 修改loading插件样式
21 | - 请求增加超时提示,超时时间为10s
22 | - vw布局插件升级postcss-px-to-viewport,支持排除node_momdules插件包,rem布局暂不支持可换插件postcss-px2rem-exclude or px2rem-exclude
23 |
24 | #### 0.3.0
25 |
26 | - 按需加载打包 chunkname
27 | - axios 优化挂载方式
28 | - less 变量 mixins全局引入,优化app.css体积 style-resources-loader
29 | - 增加常用css方案 渐变兼容IE9 一像素边框 二倍图三倍图 iphoneX适配 等
30 | - 增加常用组件库 插件库 toast comfirm alert loading等
31 | - 增加常用工具库
32 | - vw布局优化 去掉postcss-viewport-units 和viewport-units-buggyfill 给vw、vh、vmin和vmax做适配的操作。
33 | - 填补cssnano 自动计算z-index的坑
34 | - 优化css打包过大问题 优化css结构 全局引入less变量 mixins等 **style-resources-loader**
35 | ```
36 | vars.less //style-resources-loader 可在build/utils.js修改路径
37 | mixins.less //style-resources-loader
38 | common.css //index中import引入
39 | animation.css //index中import引入
40 | reset.css //index中import引入
41 | ```
42 | #### 0.2.4
43 |
44 | - 开启动态链接库dll并自动插入到模板中新增插件
45 | - DllPlugin,DllReferencePlugin,html-webpack-include-assets-plugin,cross-env
46 | - 动态链接库修改在config/dll.lib.dependencies.js 默认只用了vue,vue-router
47 | #### 0.2.2
48 |
49 | - 0.2.2 开启可配置dns预解析
50 |
51 | #### 0.2.1
52 |
53 | - 增加代码检测工作流
54 | - prettier统一代码格式
55 | - precommit自动美化格式以及修复代码
56 | - lint-staged 多人写作避免代码冲突,渐进式lint代码
57 | - 如果想要启用官方推荐的standard 可在.eslintrc.js中开启
58 |
59 |
60 | #### 0.2.0
61 |
62 | - 增加jsdoc配置 自动生成说明文档
63 | - 增加对.vue文件的文档解析 jsdoc jsdoc-vue
64 |
65 | #### 0.1.8
66 |
67 | - 增加一键生成多页面应用
68 |
69 | #### 0.1.4
70 |
71 | - 增加多页面配置
72 |
73 |
74 |
--------------------------------------------------------------------------------
/generators/app/templates/build/webpack.dll.conf.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const webpack = require("webpack");
3 | const libs = require("../config/dll.libs.dependencies.js");
4 | // const config = require("../config");
5 | // const AssetsPlugin = require("assets-webpack-plugin");
6 |
7 | const webpackConf = {
8 | entry: {
9 | ...libs
10 | },
11 |
12 | output: {
13 | // 输出的文件都放到 dist 目录下
14 | path: path.join(__dirname, "../static/libs"),
15 | // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,也就是 entry 中配置的 vue 等
16 | filename: "dll.[name].js",
17 | // 存放动态链接库的全局变量名称,例如对应 vue 来说就是 _dll_vue
18 | // 之所以在前面加上 _dll_ 是为了防止全局变量冲突
19 | // publicPath: process.env.NODE_ENV === "production" ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
20 | /**
21 | * output.library
22 | * 将会定义为 window.${output.library}
23 | * 在这次的例子中,将会定义为`window._dll_vue_library`
24 | */
25 | library: "_dll_[name]"
26 | },
27 | plugins: [
28 | new webpack.DllPlugin({
29 | // 动态链接库的全局变量名称,需要和 output.library 中保持一致
30 | // 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
31 | // 例如 vue.manifest.json 中就有 "name": "_dll_vue"
32 | path: path.join(__dirname, "../static/libs", "[name].manifest.json"),
33 | name: "_dll_[name]"
34 | }),
35 | new webpack.DefinePlugin({
36 | 'process.env': {
37 | NODE_ENV: JSON.stringify(process.env.NODE_ENV)
38 | }
39 | }),
40 |
41 | // 插入到html中
42 | // new AssetsPlugin({
43 | // filename: "bundle-config.json",
44 | // path: path.join(__dirname, '..', 'config')
45 | // })
46 |
47 | ]
48 | };
49 | // 生产环境下压缩
50 | if (process.env.NODE_ENV === 'production') {
51 | webpackConf.plugins.unshift(new webpack.optimize.UglifyJsPlugin());
52 | }
53 | module.exports = webpackConf
54 |
--------------------------------------------------------------------------------
/generators/app/templates/src/plugins/loading/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file loading 插件
3 | * @example
4 | * this.$x.loading.show('1')
5 | * this.$x.loading.show()
6 | * this.$x.loading.hide()
7 | */
8 | import Vue from "vue";
9 | import LoadingComponent from "@/components/Loading.vue";
10 | // const plagin = {
11 | // install(Vue, options) {
12 | // Vue.component(loading.name, loading) // 组件的name属性
13 | // // 类似通过 this.$xxx 方式调用插件的 其实只是挂载到原型上而已
14 | // // Vue.prototype.$xxx // 最终可以在任何地方通过 this.$xxx 调用
15 | // // 虽然没有明确规定用$开头 但是大家都默认遵守这个规定
16 | // }
17 | // }
18 | // export default plagin // 导出..
19 |
20 | export default {
21 | install(Vue, props) {
22 | const LoadingPlugin = Vue.extend(LoadingComponent);
23 |
24 | let $vm = new LoadingPlugin({
25 | el: document.createElement("div")
26 | });
27 |
28 | document.body.appendChild($vm.$el);
29 |
30 | // $vm.show = false;
31 | let loading = {
32 | show(text) {
33 | $vm.value = true;
34 |
35 | text && ($vm.text = text);
36 | },
37 | hide() {
38 | $vm.value = false;
39 | }
40 | };
41 | // const loading = {
42 | // show() {
43 | // if ($vm.show) return;
44 | // $vm.value = true;
45 | // },
46 | // hide() {
47 | // $vm.value = false;
48 | // }
49 | // };
50 | if (!Vue.$x) {
51 | Vue.$x = {
52 | loading
53 | };
54 | } else {
55 | Vue.$x.loading = loading;
56 | }
57 | // if (!Vue.$loading) {
58 | // Vue.$loading = loading;
59 | // }
60 | // Vue.prototype.$loading = Vue.$loading;
61 | Vue.mixin({
62 | created() {
63 | this.$x = Vue.$x;
64 | }
65 | });
66 | }
67 | };
68 |
--------------------------------------------------------------------------------
/generators/app/templates/src/pages/_HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 |
showAlert
6 |
showLoading
7 |
showToast
8 |
showConfirm
9 |
10 |
11 |
12 |
60 |
61 |
62 |
79 |
--------------------------------------------------------------------------------
/generators/app/templates/src/plugins/alert/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file alert插件
3 | * @example
4 | *this.$x.alert({
5 | * title: '你好',
6 | * subtitle: '我是副标题',
7 | * body:'呵呵',
8 | * delayed: true,
9 | * duration: 3000,
10 | * boxClass: ''
11 | * })
12 | * .then(val => {
13 | * console.log('change');
14 | * });
15 | */
16 |
17 | import Vue from 'vue';
18 | import Alert from '@/components/Alert.vue';
19 |
20 | const defaultProps = {
21 | delayed: true,
22 | duration: 3000
23 | }
24 |
25 | const plugin = {
26 | install(vue, props = {}) {
27 | const AlertPlugin = Vue.extend(Alert);
28 |
29 | let $vm = new AlertPlugin({
30 | el: document.createElement('div')
31 | });
32 | document.body.appendChild($vm.$el);
33 |
34 | function alert(options = {}) {
35 | if ($vm.show) return;
36 |
37 |
38 | // 如果传参为字符串,则直接显示body 的文本
39 | if (typeof options === 'string') {
40 | options = {
41 | body: arguments[0]
42 | };
43 | }
44 | //配置优选级: 组件默认配置 < 插件默认配置 < 全局配置 < 实例配置
45 | $vm = Object.assign($vm, defaultProps, props, options);
46 | $vm.show = true;
47 | // 支持延时消失 默认支持
48 | if ($vm.delayed) {
49 | setTimeout(_ => {
50 | $vm.show = false
51 | }, $vm.duration)
52 | }
53 | return new Promise((resolve, reject) => {
54 | $vm.$watch('show', val => {
55 | resolve();
56 | });
57 | });
58 | }
59 |
60 | if (!vue.$x) {
61 | vue.$x = {
62 | alert
63 | };
64 | } else {
65 | vue.$x.alert = alert;
66 | }
67 | vue.mixin({
68 | created: function() {
69 | this.$x = vue.$x;
70 | }
71 | });
72 | }
73 | };
74 |
75 | export default plugin;
76 |
--------------------------------------------------------------------------------
/generators/app/templates/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
27 |
87 |
--------------------------------------------------------------------------------
/generators/app/templates/src/plugins/toast/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file toast插件
3 | * @example
4 | * useage:
5 | * this.$x.toast('你好')
6 | * this.$x.toast({
7 | * message: '你好',
8 | * position: 'top',
9 | * duration: 2000,
10 | * toastClass: ''
11 | * })
12 | */
13 |
14 | import Vue from "vue";
15 | import Toast from "@/components/Toast";
16 |
17 | const defaultProps = {
18 | delayed: true,
19 | duration: 2000
20 | };
21 | const plugin = {
22 | install(vue, props = {}) {
23 | const ToastPlugin = Vue.extend(Toast);
24 | // toast实例 $vm
25 | let $vm = new ToastPlugin({
26 | el: document.createElement("div")
27 | });
28 | document.body.appendChild($vm.$el);
29 |
30 | function toast(options = {}) {
31 | // 如果当前显示 则return
32 | if ($vm.show) return;
33 |
34 | // 如果传参为字符串,则直接显示body 的文本
35 | if (typeof options === "string") {
36 | options = {
37 | message: arguments[0]
38 | };
39 | }
40 | //配置优选级: 默认配置 < 全局配置 < 实例配置
41 | //$vm为默认配置
42 | //install时传入的props为全局设置
43 | //调取toast时传入的options为实例配置
44 | $vm = Object.assign($vm, defaultProps, props, options);
45 | $vm.show = true;
46 | // 支持延时消失 默认支持
47 | if ($vm.delayed) {
48 | setTimeout(_ => {
49 | $vm.show = false;
50 | }, $vm.duration);
51 | }
52 | return new Promise((resolve, reject) => {
53 | $vm.$watch("show", val => {
54 | resolve();
55 | });
56 | });
57 | }
58 |
59 | if (!vue.$x) {
60 | vue.$x = {
61 | toast
62 | };
63 | } else {
64 | vue.$x.toast = toast;
65 | }
66 |
67 | vue.mixin({
68 | created: function() {
69 | this.$x = vue.$x;
70 | }
71 | });
72 | }
73 | };
74 |
75 | export default plugin;
76 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/Toast.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ message }}
5 |
6 |
7 |
8 |
62 |
90 |
--------------------------------------------------------------------------------
/generators/app/templates/src/utils/storage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 本地存储实现,封装localStorage和sessionStorage
3 | */
4 | let store = {
5 | storage: window.localStorage,
6 | session: {
7 | storage: window.sessionStorage
8 | }
9 | }
10 |
11 | const api = {
12 | set(key, val) {
13 | if (this.disabled) {
14 | return
15 | }
16 | if (val === undefined) {
17 | return this.remove(key)
18 | }
19 | this.storage.setItem(key, serialize(val))
20 | return val
21 | },
22 |
23 | get(key, def) {
24 | if (this.disabled) {
25 | return def
26 | }
27 | let val = deserialize(this.storage.getItem(key))
28 | return (val === undefined ? def : val)
29 | },
30 |
31 | has(key) {
32 | return this.get(key) !== undefined
33 | },
34 |
35 | remove(key) {
36 | if (this.disabled) {
37 | return
38 | }
39 | this.storage.removeItem(key)
40 | },
41 |
42 | clear() {
43 | if (this.disabled) {
44 | return
45 | }
46 | this.storage.clear()
47 | },
48 |
49 | getAll() {
50 | if (this.disabled) {
51 | return null
52 | }
53 | let ret = {}
54 | this.forEach((key, val) => {
55 | ret[key] = val
56 | })
57 | return ret
58 | },
59 |
60 | forEach(callback) {
61 | if (this.disabled) {
62 | return
63 | }
64 | for (let i = 0; i < this.storage.length; i++) {
65 | let key = this.storage.key(i)
66 | callback(key, this.get(key))
67 | }
68 | }
69 | }
70 |
71 | Object.assign(store, api)
72 |
73 | Object.assign(store.session, api)
74 |
75 | function serialize(val) {
76 | return JSON.stringify(val)
77 | }
78 |
79 | function deserialize(val) {
80 | if (typeof val !== 'string') {
81 | return undefined
82 | }
83 | try {
84 | return JSON.parse(val)
85 | } catch (e) {
86 | return val || undefined
87 | }
88 | }
89 |
90 | try {
91 | const testKey = '__caniuse_storage__'
92 | store.set(testKey, testKey)
93 | if (store.get(testKey) !== testKey) {
94 | store.disabled = true
95 | }
96 | store.remove(testKey)
97 | } catch (e) {
98 | store.disabled = true
99 | }
100 |
101 | export default store
102 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-easy-vue",
3 | "version": "0.4.1",
4 | "description": "a generator for a super vue project ",
5 | "homepage": "https://github.com/501981732/easy-vue",
6 | "author": {
7 | "name": "wangmeng",
8 | "email": "501981732@qq.com",
9 | "url": "https://github.com/501981732"
10 | },
11 | "files": [
12 | "generators"
13 | ],
14 | "main": "generators/index.js",
15 | "keywords": [
16 | "generator",
17 | "vue",
18 | "skeleton",
19 | "vw",
20 | "rem",
21 | "MPA",
22 | "dll",
23 | "multi-page",
24 | "jsdoc",
25 | "yeoman-generator",
26 | "eslint",
27 | "prettier",
28 | "lint-staged",
29 | "husky"
30 | ],
31 | "devDependencies": {
32 | "yeoman-test": "^1.7.0",
33 | "yeoman-assert": "^3.1.0",
34 | "coveralls": "^3.0.0",
35 | "eslint": "^5.4.0",
36 | "prettier": "^1.11.1",
37 | "husky": "^0.14.3",
38 | "lint-staged": "^7.2.2",
39 | "eslint-config-prettier": "^3.0.1",
40 | "eslint-plugin-prettier": "^2.6.0",
41 | "eslint-config-xo": "^0.24.2",
42 | "jest": "^23.5.0"
43 | },
44 | "engines": {
45 | "npm": ">= 4.0.0"
46 | },
47 | "dependencies": {
48 | "yeoman-generator": "^2.0.1",
49 | "chalk": "^2.1.0",
50 | "yosay": "^2.0.1"
51 | },
52 | "jest": {
53 | "testEnvironment": "node"
54 | },
55 | "lint-staged": {
56 | "*.js": [
57 | "eslint --fix",
58 | "git add"
59 | ],
60 | "*.json": [
61 | "prettier --write",
62 | "git add"
63 | ]
64 | },
65 | "eslintConfig": {
66 | "extends": [
67 | "xo",
68 | "prettier"
69 | ],
70 | "env": {
71 | "jest": true,
72 | "node": true
73 | },
74 | "rules": {
75 | "prettier/prettier": [
76 | "error",
77 | {
78 | "singleQuote": true,
79 | "printWidth": 90
80 | }
81 | ]
82 | },
83 | "plugins": [
84 | "prettier"
85 | ]
86 | },
87 | "scripts": {
88 | "pretest": "eslint .",
89 | "precommit": "lint-staged",
90 | "test": "jest"
91 | },
92 | "repository": "501981732/generator-easy-vue",
93 | "license": "MIT"
94 | }
95 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html,
7 | body,
8 | div,
9 | span,
10 | applet,
11 | object,
12 | iframe,
13 | h1,
14 | h2,
15 | h3,
16 | h4,
17 | h5,
18 | h6,
19 | p,
20 | blockquote,
21 | pre,
22 | a,
23 | abbr,
24 | acronym,
25 | address,
26 | big,
27 | cite,
28 | code,
29 | del,
30 | dfn,
31 | em,
32 | img,
33 | ins,
34 | kbd,
35 | q,
36 | s,
37 | samp,
38 | small,
39 | strike,
40 | strong,
41 | sub,
42 | sup,
43 | tt,
44 | var,
45 | b,
46 | u,
47 | i,
48 | center,
49 | dl,
50 | dt,
51 | dd,
52 | ol,
53 | ul,
54 | li,
55 | fieldset,
56 | form,
57 | label,
58 | legend,
59 | table,
60 | caption,
61 | tbody,
62 | tfoot,
63 | thead,
64 | tr,
65 | th,
66 | td,
67 | article,
68 | aside,
69 | canvas,
70 | details,
71 | embed,
72 | figure,
73 | figcaption,
74 | footer,
75 | header,
76 | hgroup,
77 | menu,
78 | nav,
79 | output,
80 | ruby,
81 | section,
82 | summary,
83 | time,
84 | mark,
85 | audio,
86 | video {
87 | margin: 0;
88 | padding: 0;
89 | border: 0;
90 | font-size: 100%;
91 | font: inherit;
92 | vertical-align: baseline;
93 | }
94 |
95 | /* HTML5 display-role reset for older browsers */
96 | article,
97 | aside,
98 | details,
99 | figcaption,
100 | figure,
101 | footer,
102 | header,
103 | hgroup,
104 | menu,
105 | nav,
106 | section {
107 | display: block;
108 | }
109 |
110 | body {
111 | line-height: normal;
112 | -webkit-text-size-adjust: none;
113 | min-height: 100%;
114 | /*滚动不顺畅*/
115 | -webkit-overflow-scrolling: touch;
116 | font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Hiragino Sans GB', "Microsoft YaHei", Helvetica, "\5B8B\4F53", sans-serif;
117 | /*避免动画撑开*/
118 | overflow-x: hidden;
119 | scroll-behavior: smooth;
120 | }
121 |
122 | ol,
123 | ul {
124 | list-style: none;
125 | }
126 |
127 | blockquote,
128 | q {
129 | quotes: none;
130 | }
131 |
132 | blockquote:before,
133 | blockquote:after,
134 | q:before,
135 | q:after {
136 | content: '';
137 | content: none;
138 | }
139 |
140 | table {
141 | border-collapse: collapse;
142 | border-spacing: 0;
143 | }
144 | /*补充*/
145 | input,
146 | button,
147 | textarea {
148 | border: 0;
149 | border-radius: 0;
150 | background: transparent;
151 | -webkit-appearance: none;
152 | box-sizing: border-box;
153 | outline: none;
154 | }
155 |
156 | button {
157 | outline: none;
158 | }
159 |
160 | a {
161 | text-decoration: none
162 | }
163 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/common.css:
--------------------------------------------------------------------------------
1 | /*//公共样式文件,class或id命名必须以c-为前缀开头*/
2 |
3 | .clearfix:after,
4 | .clear:before {
5 | display: block;
6 | height: 0;
7 | visibility: hidden;
8 | clear: both;
9 | content: ".";
10 | }
11 |
12 | .clearfix {
13 | /*// overflow: auto;*/
14 | zoom: 1;
15 | }
16 |
17 | [clearfix]:after,
18 | [clear]:before {
19 | display: block;
20 | height: 0;
21 | visibility: hidden;
22 | clear: both;
23 | content: ".";
24 | }
25 |
26 | [clearfix] {
27 | /*// overflow: auto;*/
28 | zoom: 1;
29 | }
30 |
31 | .fl {
32 | float: left;
33 | }
34 |
35 | .fr {
36 | float: right;
37 | }
38 |
39 |
40 | .w-10 {
41 | width: 10px;
42 | }
43 |
44 |
45 | .h-10 {
46 | height: 10px;
47 | }
48 |
49 | .h-20 {
50 | height: 20px;
51 | }
52 |
53 |
54 | .mt-10 {
55 | margin-top: 10px;
56 | }
57 |
58 |
59 | .ml-10 {
60 | margin-left: 10px;
61 | }
62 |
63 | .pt-10 {
64 | padding-top: 10px;
65 | }
66 |
67 | .pl-10 {
68 | padding-left: 10px;
69 | }
70 |
71 | .search.icon {
72 | color: #000;
73 | position: absolute;
74 | margin-top: 2px;
75 | margin-left: 3px;
76 | width: 12px;
77 | height: 12px;
78 | border: solid 1px currentColor;
79 | border-radius: 100%;
80 | transform: rotate(-45deg);
81 | }
82 |
83 | .search.icon:before {
84 | content: "";
85 | position: absolute;
86 | top: 12px;
87 | left: 5px;
88 | height: 6px;
89 | width: 1px;
90 | background-color: currentColor;
91 | }
92 |
93 | /*// 超出部分...*/
94 | .ellipsis {
95 | overflow: hidden;
96 | text-overflow: ellipsis;
97 | white-space: nowrap;
98 | }
99 |
100 | /*// 垂直居中*/
101 | .center_table {
102 | display: table;
103 | }
104 |
105 | .center_cell {
106 | display: table-cell;
107 | vertical-align: middle;
108 | text-align: center;
109 | }
110 |
111 | .no-scrollbar {
112 | &::-webkit-scrollbar {
113 | display: none;
114 | }
115 | }
116 | /*// 蒙层*/
117 | .c-mask {
118 | position: fixed;
119 | top: 0;
120 | left: 0;
121 | bottom: 0;
122 | right: 0;
123 | height: 100%;
124 | background: rgba(0, 0, 0, .7);
125 | z-index: 1000;
126 | }
127 | /*// 蒙层box居中*/
128 | .c-center-box {
129 | position: fixed;
130 | top: 50%;
131 | left: 50%;
132 | transform: translate(-50%, -50%);
133 | width: 80%;
134 | z-index: 1001;
135 | text-align: center;
136 | }
137 |
138 | .gpu {
139 | transform: translateZ(0);
140 | }
141 | .iphoneX {
142 | /*meta viewport-fit=cover*/
143 | box-sizing: content-box;
144 | padding-bottom: constant(safe-area-inset-bottom);
145 | padding-bottom: env(safe-area-inset-bottom);
146 | }
147 |
148 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/textCarousel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ text }}
6 |
7 |
8 |
9 |
10 |
11 |
77 |
96 |
--------------------------------------------------------------------------------
/generators/publicPath/templates/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | // "/yy": {
15 | // target: "http://zp.58.com/",
16 | // secure: false,
17 | // changeOrigin: true,
18 | // }
19 | },
20 |
21 | // Various Dev Server settings
22 | host: 'localhost', // can be overwritten by process.env.HOST
23 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
24 | autoOpenBrowser: true,
25 | errorOverlay: true,
26 | notifyOnErrors: true,
27 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
28 | // Use Eslint Loader?
29 | // If true, your code will be linted during bundling and
30 | // linting errors and warnings will be shown in the console.
31 | useEslint: true,
32 | // If true, eslint errors and warnings will also be shown in the error overlay
33 | // in the browser.
34 | showEslintErrorsInOverlay: false,
35 |
36 | /**
37 | * Source Maps
38 | */
39 |
40 | // https://webpack.js.org/configuration/devtool/#development
41 | devtool: 'cheap-module-eval-source-map',
42 |
43 | // If you have problems debugging vue-files in devtools,
44 | // set this to false - it *may* help
45 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
46 | cacheBusting: true,
47 |
48 | cssSourceMap: true
49 | },
50 |
51 | build: {
52 | // Template for index.html
53 | index: path.resolve(__dirname, '../dist/index.html'),
54 |
55 | // Paths
56 | assetsRoot: path.resolve(__dirname, '../dist'),
57 | assetsSubDirectory: 'static',
58 | assetsPublicPath: '<%= publicPath%>', //j1.58cdn.com.cn/crop/baseteam/yunying/xxx/
59 | cssPublicPath: '',
60 | imagePublicPath: '', //img.58cdn.com.cn/crop/baseteam/yunying/xxx/img/
61 | /**
62 | * Source Maps
63 | */
64 |
65 | productionSourceMap: false,//map文件
66 | // https://webpack.js.org/configuration/devtool/#production
67 | devtool: '#source-map',
68 |
69 | // Gzip off by default as many popular static hosts such as
70 | // Surge or Netlify already gzip all static assets for you.
71 | // Before setting to `true`, make sure to:
72 | // npm install --save-dev compression-webpack-plugin
73 | productionGzip: false,
74 | productionGzipExtensions: ['js', 'css'],
75 |
76 | // Run the build command with an extra argument to
77 | // View the bundle analyzer report after build finishes:
78 | // `npm run build --report`
79 | // Set to `true` or `false` to always turn it on or off
80 | bundleAnalyzerReport: process.env.npm_config_report
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/generators/imagePublicPath/templates/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | // "/yy": {
15 | // target: "http://zp.58.com/",
16 | // secure: false,
17 | // changeOrigin: true,
18 | // }
19 | },
20 |
21 | // Various Dev Server settings
22 | host: 'localhost', // can be overwritten by process.env.HOST
23 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
24 | autoOpenBrowser: true,
25 | errorOverlay: true,
26 | notifyOnErrors: true,
27 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
28 | // Use Eslint Loader?
29 | // If true, your code will be linted during bundling and
30 | // linting errors and warnings will be shown in the console.
31 | useEslint: true,
32 | // If true, eslint errors and warnings will also be shown in the error overlay
33 | // in the browser.
34 | showEslintErrorsInOverlay: false,
35 |
36 | /**
37 | * Source Maps
38 | */
39 |
40 | // https://webpack.js.org/configuration/devtool/#development
41 | devtool: 'cheap-module-eval-source-map',
42 |
43 | // If you have problems debugging vue-files in devtools,
44 | // set this to false - it *may* help
45 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
46 | cacheBusting: true,
47 |
48 | cssSourceMap: true
49 | },
50 |
51 | build: {
52 | // Template for index.html
53 | index: path.resolve(__dirname, '../dist/index.html'),
54 |
55 | // Paths
56 | assetsRoot: path.resolve(__dirname, '../dist'),
57 | assetsSubDirectory: 'static',
58 | assetsPublicPath: '', //j1.58cdn.com.cn/crop/baseteam/yunying/xxx/
59 | cssPublicPath: '',
60 | imagePublicPath: '<%= imagePublicPath%>', //img.58cdn.com.cn/crop/baseteam/yunying/xxx/img/
61 | /**
62 | * Source Maps
63 | */
64 |
65 | productionSourceMap: false,//map文件
66 | // https://webpack.js.org/configuration/devtool/#production
67 | devtool: '#source-map',
68 |
69 | // Gzip off by default as many popular static hosts such as
70 | // Surge or Netlify already gzip all static assets for you.
71 | // Before setting to `true`, make sure to:
72 | // npm install --save-dev compression-webpack-plugin
73 | productionGzip: false,
74 | productionGzipExtensions: ['js', 'css'],
75 |
76 | // Run the build command with an extra argument to
77 | // View the bundle analyzer report after build finishes:
78 | // `npm run build --report`
79 | // Set to `true` or `false` to always turn it on or off
80 | bundleAnalyzerReport: process.env.npm_config_report
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/generators/app/templates/config/_index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {
14 | // "/yy": {
15 | // target: "http://zp.58.com/",
16 | // secure: false,
17 | // changeOrigin: true,
18 | // }
19 | },
20 |
21 | // Various Dev Server settings
22 | host: 'localhost', // can be overwritten by process.env.HOST
23 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
24 | autoOpenBrowser: true,
25 | errorOverlay: true,
26 | notifyOnErrors: true,
27 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
28 | // Use Eslint Loader?
29 | // If true, your code will be linted during bundling and
30 | // linting errors and warnings will be shown in the console.
31 | useEslint: true,
32 | // If true, eslint errors and warnings will also be shown in the error overlay
33 | // in the browser.
34 | showEslintErrorsInOverlay: false,
35 |
36 | /**
37 | * Source Maps
38 | */
39 |
40 | // https://webpack.js.org/configuration/devtool/#development
41 | devtool: 'cheap-module-eval-source-map',
42 |
43 | // If you have problems debugging vue-files in devtools,
44 | // set this to false - it *may* help
45 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
46 | cacheBusting: true,
47 |
48 | cssSourceMap: true
49 | },
50 |
51 | build: {
52 | // Template for index.html
53 | index: path.resolve(__dirname, '../dist/index.html'),
54 |
55 | // Paths
56 | assetsRoot: path.resolve(__dirname, '../dist'),
57 | assetsSubDirectory: 'static',
58 | assetsPublicPath: '<%= publicPath%>', //j1.58cdn.com.cn/crop/baseteam/yunying/xxx/
59 | cssPublicPath: '',
60 | imagePublicPath: '<%= imagePublicPath%>', //img.58cdn.com.cn/crop/baseteam/yunying/xxx/img/
61 | /**
62 | * Source Maps
63 | */
64 |
65 | productionSourceMap: false,//map文件
66 | // https://webpack.js.org/configuration/devtool/#production
67 | devtool: '#source-map',
68 |
69 | // Gzip off by default as many popular static hosts such as
70 | // Surge or Netlify already gzip all static assets for you.
71 | // Before setting to `true`, make sure to:
72 | // npm install --save-dev compression-webpack-plugin
73 | productionGzip: false,
74 | productionGzipExtensions: ['js', 'css'],
75 |
76 | // Run the build command with an extra argument to
77 | // View the bundle analyzer report after build finishes:
78 | // `npm run build --report`
79 | // Set to `true` or `false` to always turn it on or off
80 | bundleAnalyzerReport: process.env.npm_config_report,
81 | purgecssPath: [
82 | path.join(__dirname, './../src/index.html'),
83 | path.join(__dirname, './../src/*.vue'),
84 | path.join(__dirname, './../src/**/*.css'),
85 | path.join(__dirname, './../src/**/*.less'),
86 | path.join(__dirname, './../src/**/*.vue'),
87 | path.join(__dirname, './../src/**/**/*.css'),
88 | path.join(__dirname, './../src/**/**/*.less'),
89 | path.join(__dirname, './../src/**/**/*.vue'),
90 | path.join(__dirname, './../src/**/**/**/*.vue'),
91 | ]
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/generators/app/templates/build/_utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const packageConfig = require('../package.json')
6 |
7 | exports.assetsPath = function(_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' ?
9 | config.build.assetsSubDirectory :
10 | config.dev.assetsSubDirectory
11 |
12 | return path.posix.join(assetsSubDirectory, _path)
13 | }
14 |
15 | exports.cssLoaders = function(options) {
16 | options = options || {}
17 |
18 | const cssLoader = {
19 | loader: 'css-loader',
20 | options: {
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | const postcssLoader = {
26 | loader: 'postcss-loader',
27 | options: {
28 | sourceMap: options.sourceMap
29 | }
30 | }
31 |
32 | // generate loader string to be used with extract text plugin
33 | function generateLoaders(loader, loaderOptions) {
34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35 |
36 | if (loader) {
37 | loaders.push({
38 | loader: loader + '-loader',
39 | options: Object.assign({}, loaderOptions, {
40 | sourceMap: options.sourceMap,
41 | })
42 | })
43 | if (loader === 'less') {
44 | loaders.push({
45 | loader: 'style-resources-loader',
46 | options: {
47 | patterns: [
48 | path.resolve(__dirname, '../src/assets/css/vars.less'),
49 | path.resolve(__dirname, '../src/assets/css/mixins.less'),
50 | ],
51 | injector: 'append'
52 | }
53 | })
54 | }
55 | }
56 |
57 | // Extract CSS when that option is specified
58 | // (which is the case during production build)
59 | if (options.extract) {
60 | return ExtractTextPlugin.extract({
61 | use: loaders,
62 | fallback: 'vue-style-loader'
63 | })
64 | } else {
65 | return ['vue-style-loader'].concat(loaders)
66 | }
67 | }
68 |
69 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
70 | return {
71 | css: generateLoaders(),
72 | postcss: generateLoaders(),
73 | less: generateLoaders('less'),
74 | sass: generateLoaders('sass', { indentedSyntax: true }),
75 | scss: generateLoaders('sass'),
76 | stylus: generateLoaders('stylus'),
77 | styl: generateLoaders('stylus')
78 | }
79 | }
80 |
81 | // Generate loaders for standalone style files (outside of .vue)
82 | exports.styleLoaders = function(options) {
83 | const output = []
84 | const loaders = exports.cssLoaders(options)
85 |
86 | for (const extension in loaders) {
87 | const loader = loaders[extension]
88 | output.push({
89 | test: new RegExp('\\.' + extension + '$'),
90 | use: loader
91 | })
92 | }
93 |
94 | return output
95 | }
96 |
97 | exports.createNotifierCallback = () => {
98 | const notifier = require('node-notifier')
99 |
100 | return (severity, errors) => {
101 | if (severity !== 'error') return
102 |
103 | const error = errors[0]
104 | const filename = error.file && error.file.split('!').pop()
105 |
106 | notifier.notify({
107 | title: packageConfig.name,
108 | message: severity + ': ' + error.name,
109 | subtitle: filename || '',
110 | icon: path.join(__dirname, 'logo.png')
111 | })
112 | }
113 | }
114 | // 多页面entry
115 | <% if (projectType == 'MPA') {%>
116 | const glob = require('glob')
117 | exports.getEntry = (globPath, type = 'js') => {
118 | return glob.sync(globPath).reduce(function(prev, curr) {
119 | type == 'js' ? prev[curr.slice(6, -3)] = curr : prev[curr.slice(6, -5)] = curr
120 | return prev;
121 | }, {});
122 | }
123 | <%}%>
124 | // { 'module/fairs/index': './src/module/fairs/index.js',
125 | // 'module/shop/index': './src/module/shop/index.js' }
126 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/vwDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |

8 |
9 |
10 |
11 |
12 |

13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |

22 |
23 |
24 |
25 |
26 |

27 |
28 |
29 |
30 |
31 |
32 |
33 |

34 |
35 |
36 |
37 |
38 |

39 |
40 |
41 |
42 |
43 |
44 |
45 |
56 |
57 |
178 |
--------------------------------------------------------------------------------
/generators/app/templates/build/_webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | // const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
12 | // const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
13 | const portfinder = require('portfinder')
14 |
15 | const HOST = process.env.HOST
16 | const PORT = process.env.PORT && Number(process.env.PORT)
17 |
18 | // 防止报错 filter module rules
19 | baseWebpackConfig.module.rules.forEach((item,index) => {
20 | if(item.use && Array.isArray(item.use)) {
21 | baseWebpackConfig.module.rules[index].use = item.use.filter(Boolean)
22 | }
23 | })
24 | <% if(projectType =='MPA'){ %>
25 | // 多页面配置
26 | const glob = require('glob');
27 | const htmls = glob.sync('./src/modules/**/*.html').map(function (item) {
28 | var names = item.split('/')
29 | return new HtmlWebpackPlugin({
30 | // filename: './'+ names[2]+'/'+names[4], //相当于url
31 | filename: './' + names[4], //相当于url './main.html'
32 | template: item, //模板路径 './src/modules/**/*.html'
33 | inject: true,
34 | chunks:[item.slice(6, -5),'vendor','manifest']
35 | });
36 | });<% }%>
37 |
38 | const devWebpackConfig = merge(baseWebpackConfig, {
39 | module: {
40 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
41 | },
42 | // cheap-module-eval-source-map is faster for development
43 | devtool: config.dev.devtool,
44 |
45 | // these devServer options should be customized in /config/index.js
46 | devServer: {
47 | clientLogLevel: 'warning',
48 | historyApiFallback: {
49 | rewrites: [
50 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
51 | ],
52 | },
53 | hot: true,
54 | contentBase: false, // since we use CopyWebpackPlugin.
55 | compress: true,
56 | host: HOST || config.dev.host,
57 | port: PORT || config.dev.port,
58 | open: config.dev.autoOpenBrowser,
59 | overlay: config.dev.errorOverlay
60 | ? { warnings: false, errors: true }
61 | : false,
62 | publicPath: config.dev.assetsPublicPath,
63 | proxy: config.dev.proxyTable,
64 | quiet: true, // necessary for FriendlyErrorsPlugin
65 | watchOptions: {
66 | poll: config.dev.poll,
67 | }
68 | },
69 | plugins: [
70 | new webpack.DefinePlugin({
71 | 'process.env': require('../config/dev.env')
72 | }),
73 | new webpack.HotModuleReplacementPlugin(),
74 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
75 | new webpack.NoEmitOnErrorsPlugin(),
76 | // https://github.com/ampedandwired/html-webpack-plugin
77 | <% if(projectType =='SPA'){ %>
78 | new HtmlWebpackPlugin({
79 | filename: 'index.html',
80 | template: 'index.html',
81 | inject: true
82 | }),<% }%>
83 | // copy custom static assets
84 | new CopyWebpackPlugin([
85 | {
86 | from: path.resolve(__dirname, '../static'),
87 | to: config.dev.assetsSubDirectory,
88 | ignore: ['.*']
89 | }
90 | ]),
91 | // new ExtractTextPlugin({
92 | // filename: utils.assetsPath('css/[name].[contenthash].css'),
93 | // allChunks: true,
94 | // }),
95 | // new SkeletonWebpackPlugin({
96 | // webpackConfig: require('./webpack.skeleton.conf'),
97 | // quiet: true
98 | // }),
99 | ]<% if(projectType =='MPA'){ %>.concat(htmls)<%}%>
100 | })
101 |
102 | module.exports = new Promise((resolve, reject) => {
103 | portfinder.basePort = process.env.PORT || config.dev.port
104 | portfinder.getPort((err, port) => {
105 | if (err) {
106 | reject(err)
107 | } else {
108 | // publish the new Port, necessary for e2e tests
109 | process.env.PORT = port
110 | // add port to devServer config
111 | devWebpackConfig.devServer.port = port
112 |
113 | // Add FriendlyErrorsPlugin
114 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
115 | compilationSuccessInfo: {
116 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
117 | },
118 | onErrors: config.dev.notifyOnErrors
119 | ? utils.createNotifierCallback()
120 | : undefined
121 | }))
122 |
123 | resolve(devWebpackConfig)
124 | }
125 | })
126 | })
127 |
--------------------------------------------------------------------------------
/generators/app/templates/build/_webpack.test.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | // const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
12 | // const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
13 | const portfinder = require('portfinder')
14 |
15 | const HOST = process.env.HOST
16 | const PORT = process.env.PORT && Number(process.env.PORT)
17 |
18 | // 防止报错 filter module rules
19 | baseWebpackConfig.module.rules.forEach((item,index) => {
20 | if(item.use && Array.isArray(item.use)) {
21 | baseWebpackConfig.module.rules[index].use = item.use.filter(Boolean)
22 | }
23 | })
24 | <% if(projectType =='MPA'){ %>
25 | // 多页面配置
26 | const glob = require('glob');
27 | const htmls = glob.sync('./src/modules/**/*.html').map(function (item) {
28 | var names = item.split('/')
29 | return new HtmlWebpackPlugin({
30 | // filename: './'+ names[2]+'/'+names[4], //相当于url
31 | filename: './' + names[4], //相当于url './main.html'
32 | template: item, //模板路径 './src/modules/**/*.html'
33 | inject: true,
34 | chunks:[item.slice(6, -5),'vendor','manifest']
35 | });
36 | });<% }%>
37 |
38 | const devWebpackConfig = merge(baseWebpackConfig, {
39 | module: {
40 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
41 | },
42 | // cheap-module-eval-source-map is faster for development
43 | devtool: config.dev.devtool,
44 |
45 | // these devServer options should be customized in /config/index.js
46 | devServer: {
47 | clientLogLevel: 'warning',
48 | historyApiFallback: {
49 | rewrites: [
50 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
51 | ],
52 | },
53 | hot: true,
54 | contentBase: false, // since we use CopyWebpackPlugin.
55 | compress: true,
56 | host: HOST || config.dev.host,
57 | port: PORT || config.dev.port,
58 | open: config.dev.autoOpenBrowser,
59 | overlay: config.dev.errorOverlay
60 | ? { warnings: false, errors: true }
61 | : false,
62 | publicPath: config.dev.assetsPublicPath,
63 | proxy: config.dev.proxyTable,
64 | quiet: true, // necessary for FriendlyErrorsPlugin
65 | watchOptions: {
66 | poll: config.dev.poll,
67 | }
68 | },
69 | plugins: [
70 | new webpack.DefinePlugin({
71 | 'process.env': require('../config/test.env')
72 | }),
73 | new webpack.HotModuleReplacementPlugin(),
74 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
75 | new webpack.NoEmitOnErrorsPlugin(),
76 | // https://github.com/ampedandwired/html-webpack-plugin
77 | <% if(projectType =='SPA'){ %>
78 | new HtmlWebpackPlugin({
79 | filename: 'index.html',
80 | template: 'index.html',
81 | inject: true
82 | }),<% }%>
83 | // copy custom static assets
84 | new CopyWebpackPlugin([
85 | {
86 | from: path.resolve(__dirname, '../static'),
87 | to: config.dev.assetsSubDirectory,
88 | ignore: ['.*']
89 | }
90 | ]),
91 | // new ExtractTextPlugin({
92 | // filename: utils.assetsPath('css/[name].[contenthash].css'),
93 | // allChunks: true,
94 | // }),
95 | // new SkeletonWebpackPlugin({
96 | // webpackConfig: require('./webpack.skeleton.conf'),
97 | // quiet: true
98 | // }),
99 | ]<% if(projectType =='MPA'){ %>.concat(htmls)<%}%>
100 | })
101 |
102 | module.exports = new Promise((resolve, reject) => {
103 | portfinder.basePort = process.env.PORT || config.dev.port
104 | portfinder.getPort((err, port) => {
105 | if (err) {
106 | reject(err)
107 | } else {
108 | // publish the new Port, necessary for e2e tests
109 | process.env.PORT = port
110 | // add port to devServer config
111 | devWebpackConfig.devServer.port = port
112 |
113 | // Add FriendlyErrorsPlugin
114 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
115 | compilationSuccessInfo: {
116 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
117 | },
118 | onErrors: config.dev.notifyOnErrors
119 | ? utils.createNotifierCallback()
120 | : undefined
121 | }))
122 |
123 | resolve(devWebpackConfig)
124 | }
125 | })
126 | })
127 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/Loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
51 |
170 |
--------------------------------------------------------------------------------
/generators/app/templates/build/_webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 | const DllReferencePlugin = require("webpack/lib/DllReferencePlugin");
7 | //将dll文件插入
8 | const HtmlWebpackIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');
9 |
10 | function resolve(dir) {
11 | return path.join(__dirname, '..', dir)
12 | }
13 | <% if (eslint) {%>
14 | const createLintingRule = () => ({
15 | test: /\.(js|vue)$/,
16 | loader: "eslint-loader",
17 | enforce: "pre",
18 | include: [resolve("src"), resolve("test")],
19 | options: {
20 | formatter: require("eslint-friendly-formatter"),
21 | emitWarning: !config.dev.showEslintErrorsInOverlay
22 | }
23 | });
24 | <% }%>
25 | const ISPROD = process.env.NODE_ENV === 'production'
26 |
27 | const IMAGE_NAME = ISPROD ? '[name].[ext]' : utils.assetsPath('img/[name].[ext]')
28 |
29 | const IMAGE_LOADER_QUERY = ISPROD ? `&name=${IMAGE_NAME}&outputPath=/img&publicPath=${config.build.imagePublicPath}` : `&name=${IMAGE_NAME}`
30 |
31 | //上线前打包压缩图片 开发环境禁用
32 | const IMAGELOADER = ISPROD ? `image-webpack-loader?{mozjpeg: {progressive: true,quality: 65},pngquant:{quality: "55-90", speed: 4}}` : null
33 |
34 | module.exports = {
35 | context: path.resolve(__dirname, '../'),
36 | <% if (projectType == 'SPA') {%>
37 | entry: {
38 | app: './src/main.js'
39 | },
40 | <% } else { %>
41 | entry: utils.getEntry('./src/modules/**/*.js'), // 获得入口js文件,
42 | <% }%>
43 | output: {
44 | path: config.build.assetsRoot,
45 | filename: '[name].js',
46 | publicPath: process.env.NODE_ENV === 'production' ?
47 | config.build.assetsPublicPath : config.dev.assetsPublicPath
48 | },
49 | resolve: {
50 | extensions: ['.js', '.vue', '.json'],
51 | alias: {
52 | 'vue$': 'vue/dist/vue.esm.js',
53 | '@': resolve('src'),
54 | }
55 | },
56 | module: {
57 | rules: [
58 | <% if (eslint) {%>...(config.dev.useEslint ? [createLintingRule()] : []), <% }%> {
59 | test: /\.vue$/,
60 | loader: 'vue-loader',
61 | options: vueLoaderConfig
62 | }, {
63 | test: /\.js$/,
64 | loader: 'babel-loader',
65 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
66 | }, {
67 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
68 | // loader: 'url-loader',
69 | // options: {
70 | // limit: 10000,
71 | // name: utils.assetsPath('img/[name].[ext]')
72 | use: [
73 | `url-loader?limit=10000${IMAGE_LOADER_QUERY}`,
74 | // IMAGELOADER,
75 | ]
76 | }, {
77 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
78 | loader: 'url-loader',
79 | options: {
80 | limit: 10000,
81 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
82 | }
83 | }, {
84 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
85 | loader: 'url-loader',
86 | options: {
87 | limit: 10000,
88 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
89 | }
90 | }
91 | ]
92 | },
93 | node: {
94 | // prevent webpack from injecting useless setImmediate polyfill because Vue
95 | // source contains it (although only uses it if it's native).
96 | setImmediate: false,
97 | // prevent webpack from injecting mocks to Node native modules
98 | // that does not make sense for the client
99 | dgram: 'empty',
100 | fs: 'empty',
101 | net: 'empty',
102 | tls: 'empty',
103 | child_process: 'empty'
104 | },
105 | // externals: {
106 | // 'vue': 'Vue',
107 | // 'vue-router': 'VueRouter',
108 | // 'axios': 'axios',
109 | // },
110 | plugins: [
111 | // 告诉 Webpack 使用了哪些动态链接库
112 | new DllReferencePlugin({
113 | // 描述 vue 动态链接库的文件内容
114 | manifest: require('../static/libs/dll_vendor.manifest.json'),
115 | }),
116 | //将打包的动态链接库插入到html模板中
117 | new HtmlWebpackIncludeAssetsPlugin({
118 | assets: ["static/libs/dll.dll_vendor.js"],
119 | append: false,
120 | hash: false,
121 | publicPath: process.env.NODE_ENV === "production" ?
122 | config.build.assetsPublicPath : config.dev.assetsPublicPath
123 | })
124 | ]
125 | }
126 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/Alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ title }}
7 |
8 | {{ subtitle }}
9 |
10 |
11 | {{ body }}
12 |
13 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
87 |
173 |
--------------------------------------------------------------------------------
/generators/app/templates/src/components/Confirm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
{{ body }}
11 |
12 |
13 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
82 |
169 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/mixins.less:
--------------------------------------------------------------------------------
1 | // 箭头
2 |
3 | .down-arrow(@color:#bec8ca) {
4 | position: relative;
5 | &:after {
6 | content: "";
7 | border-left: 2px solid @color;
8 | border-top: 2px solid @color;
9 | transform: translateY(-50%) rotate(-135deg);
10 | //为了更准确的居中,添加translateY(-50%),即上移自身的50%。注意必须写在rotate前面,否则坐标系被旋转后再平移达不到想要的效果
11 | display: inline-block;
12 | height: 8px;
13 | width: 8px;
14 | position: absolute;
15 | top: 50%;
16 | right: 2px;
17 | }
18 | }
19 | .up-arrow(@color:#bec8ca) {
20 | position: relative;
21 | &:after {
22 | content: "";
23 | border-left: 2px solid @color;
24 | border-top: 2px solid @color;
25 | transform: translateY(-50%) rotate(45deg);
26 | display: inline-block;
27 | height: 8px;
28 | width: 8px;
29 | position: absolute;
30 | top: 50%;
31 | right: 2px;
32 | }
33 | }
34 | .right-arrow(@color:#bec8ca) {
35 | position: relative;
36 | &:after {
37 | content: "";
38 | border-left: 2px solid @color;
39 | border-top: 2px solid @color;
40 | transform: translateY(-50%) rotate(135deg);
41 | display: inline-block;
42 | height: 8px;
43 | width: 8px;
44 | position: absolute;
45 | top: 50%;
46 | right: 2px;
47 | }
48 | }
49 | // m 一像素边框
50 | .one-px-top(@color:#fff) {
51 | position: relative;
52 |
53 | &:before {
54 | position: absolute;
55 | content: "";
56 | left: 0;
57 | top: 0;
58 | height: 1px;
59 | width: 100%;
60 | background-color: @color;
61 | transform: scaleY(0.5);
62 | }
63 | }
64 |
65 | .one-px-bottom(@color:#fff) {
66 | position: relative;
67 |
68 | &:after {
69 | position: absolute;
70 | content: "";
71 | left: 0;
72 | bottom: 0;
73 | height: 1px;
74 | width: 100%;
75 | background-color: @color;
76 | transform: scaleY(0.5);
77 | }
78 | }
79 |
80 | .one-px-right(@color:#fff) {
81 | position: relative;
82 |
83 | &:after {
84 | position: absolute;
85 | content: "";
86 | right: 0;
87 | top: 0;
88 | width: 1px;
89 | height: 100%;
90 | background-color: @color;
91 | transform: scaleX(0.5);
92 | }
93 | }
94 |
95 | .one-px-left(@color:#fff) {
96 | position: relative;
97 |
98 | &:before {
99 | position: absolute;
100 | content: "";
101 | left: 0;
102 | top: 0;
103 | width: 1px;
104 | height: 100%;
105 | background-color: @color;
106 | transform: scaleX(0.5);
107 | }
108 | }
109 |
110 | .one-px-button(@color:#fff) {
111 | position: relative;
112 |
113 | &:after {
114 | content: " ";
115 | width: 200%;
116 | height: 200%;
117 | position: absolute;
118 | top: 0;
119 | left: 0;
120 | border: 1px solid @color;
121 | transform: scale(0.5);
122 | transform-origin: 0 0;
123 | box-sizing: border-box;
124 | border-radius: 10px;
125 | }
126 | }
127 |
128 | .one-px-box(@color:#fff) {
129 | position: relative;
130 |
131 | &:after {
132 | content: " ";
133 | width: 200%;
134 | height: 200%;
135 | position: absolute;
136 | top: 0;
137 | left: 0;
138 | border: 1px solid @color;
139 | transform: scale(0.5);
140 | transform-origin: 0 0;
141 | box-sizing: border-box;
142 | border-radius: 10px;
143 | // 事件击穿
144 | pointer-events: none;
145 | }
146 | }
147 |
148 | // 二倍图 三倍图
149 | .bg-image(@url) {
150 | background-image:~"url('@{url}@2x.png')";
151 | @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio:3) {
152 | background-image:~"url('@{url}@3x.png')";
153 | }
154 | }
155 |
156 | // 角度渐变 三色
157 | .linear-gradient(@deg: -180deg, @start: #4771ec,@startPos: 0%,@minddle: #4768ea, @middlePos: 20%, @end: #2731cd, @endPos: 100%) {
158 | filter: progid:DXImageTransform.Microsoft.Gradient(gradientType=0, startColorStr=@start, endColorStr=@end);
159 | background: linear-gradient(
160 | @deg,
161 | @start @startPos,
162 | @minddle @middlePos,
163 | @end @endPos
164 | );
165 | }
166 | // 两色渐变 两色
167 | .linear-gradient2(@deg: to bottom, @start: #4771ec,@startPos: 0%, @end: #2731cd, @endPos: 100%) {
168 | filter: progid:DXImageTransform.Microsoft.Gradient(gradientType=0, startColorStr=@start, endColorStr=@end);
169 | background: linear-gradient(
170 | @deg,
171 | @start @startPos,
172 | @end @endPos
173 | );
174 | }
175 |
176 | .c-zoom-time(@time: 4s,@type: ease-in-out, @delay:0s) {
177 | animation: zoomIn2 @time @type @delay infinite;
178 | }
179 | @keyframes zoomIn2 {
180 | from {
181 | transform: scale(.95);
182 | }
183 |
184 | 50% {
185 | transform: scale(1.05);
186 | }
187 |
188 | 100% {
189 | transform: scale(.95);
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/generators/app/templates/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= projectName%>",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "<%= author%> <%= email%>",
6 | "private": true,
7 | "scripts": {<% if(skeleton){ %>
8 | "skeleton": "webpack --config build/webpack.skeleton.conf.js && node skeleton.js",<% }%>
9 | "dll:dev": "cross-env NODE_ENV=development webpack --config build/webpack.dll.conf.js",
10 | "dll:build": "cross-env NODE_ENV=production webpack --config build/webpack.dll.conf.js",
11 | "dev": "npm run dll:dev && webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
12 | "dev:test": "npm run dll:dev && webpack-dev-server --inline --progress --config build/webpack.test.conf.js",
13 | "start": "npm run dev",<% if (eslint) {%>
14 | "eslint": "eslint --ext .js,.vue src",
15 | "eslint:fix": "eslint --fix --ext .js,.vue src",
16 | "lint-staged": "lint-staged",
17 | "prettier": "prettier --tab-width 4 --write \"./src/**/*.{js,vue,jsx,css,less,sass,scss,md,json}\"",
18 | "precommit": "lint-staged",
19 | "prebuild": "npm run dll:build && npm run eslint",<% }%>
20 | "jsdoc": "jsdoc -c ./jsdoc.conf.json -R ./README.md",
21 | "build": "node build/build.js"
22 | },<% if(eslint){ %>
23 | "pre-push": [],
24 | "lint-staged": {
25 | "src/**/*.{js,vue,jsx,sass,scss,md,json}": [
26 | "prettier --tab-width 4 --write",
27 | "eslint --fix",
28 | "git add"
29 | ]
30 | },<% }%>
31 | "dependencies": {<% if(layout === 'rem'){ %>
32 | "fastclick": "^1.0.6",
33 | "amfe-flexible": "^2.2.1",<% } else if (layout === 'vw') {%>
34 | "fastclick": "^1.0.6",<% }%>
35 | "axios": "^0.18.0",<% if(vuex){ %>
36 | "vuex": "^3.0.1",<% }%>
37 | "vue": "^2.5.2",
38 | "vue-router": "^3.0.1"
39 | },
40 | "devDependencies": {
41 | "autoprefixer": "^7.1.2",
42 | "babel-core": "^6.22.1",<% if (eslint) {%>
43 | "babel-eslint": "^10.0.1",
44 | "eslint": "^5.9.0",
45 | "eslint-config-standard": "^12.0.0",
46 | "eslint-friendly-formatter": "^4.0.1",
47 | "eslint-loader": "^2.1.1",
48 | "eslint-plugin-import": "^2.14.0",
49 | "eslint-plugin-node": "^8.0.0",
50 | "eslint-plugin-promise": "^4.0.1",
51 | "eslint-plugin-standard": "^4.0.0",
52 | "eslint-plugin-vue": "^4.7.1",
53 | "lint-staged": "^8.1.0",
54 | "prettier": "^1.15.3",
55 | "purgecss-webpack-plugin": "^1.5.0",
56 | "husky": "^1.2.0",<% }%>
57 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
58 | "babel-loader": "^7.1.1",
59 | "babel-plugin-syntax-jsx": "^6.18.0",
60 | "babel-plugin-transform-runtime": "^6.22.0",
61 | "babel-plugin-transform-vue-jsx": "^3.5.0",
62 | "babel-polyfill": "^6.26.0",
63 | "babel-preset-env": "^1.3.2",
64 | "babel-preset-stage-2": "^6.22.0",
65 | "chalk": "^2.0.1",
66 | "copy-webpack-plugin": "^4.0.1",
67 | "cross-env": "^5.2.0",
68 | "css-loader": "^0.28.0",<% if(layout === 'vw'){ %>
69 | "cssnano": "^4.1.7",
70 | "cssnano-preset-advanced": "^4.0.5",
71 | "postcss-aspect-ratio-mini": "^0.0.2",
72 | "postcss-cssnext": "^3.1.0",
73 | "postcss-px-to-viewport": "^1.1.0",
74 | "postcss-write-svg": "^3.0.1",<% }%>
75 | "extract-text-webpack-plugin": "^3.0.0",
76 | "file-loader": "^1.1.4",
77 | "friendly-errors-webpack-plugin": "^1.6.1",<% if(projectType === 'MPA'){ %>
78 | "glob": "^7.1.3",<% }%>
79 | "glob-all": "^3.1.0",
80 | "html-webpack-include-assets-plugin": "^1.0.6",
81 | "html-webpack-plugin": "^2.30.1",<% if(cssPrepeocessor === 'less'){ %>
82 | "jsdoc": "^3.5.5",
83 | "jsdoc-vue": "^1.0.0",
84 | "less": "^3.8.1",
85 | "less-loader": "^4.1.0",<% }%>
86 | "node-notifier": "^5.1.2",<% if(cssPrepeocessor === 'scss'){ %>
87 | "node-sass": "^4.10.0",
88 | "sass-loader": "^7.1.0",<% }%>
89 | "optimize-css-assets-webpack-plugin": "^3.2.0",
90 | "ora": "^1.2.0",
91 | "portfinder": "^1.0.13",
92 | "postcss-import": "^11.0.0",
93 | "postcss-loader": "^2.0.8",<% if(layout === 'rem'){ %>
94 | "postcss-pxtorem": "^4.0.1",<% }%>
95 | "postcss-url": "^7.2.1",
96 | "rimraf": "^2.6.0",
97 | "semver": "^5.3.0",
98 | "shelljs": "^0.7.6",
99 | "style-resources-loader": "^1.2.1",
100 | "uglifyjs-webpack-plugin": "^1.1.1",
101 | "url-loader": "^0.5.8",
102 | "vue-loader": "^13.3.0",<% if(skeleton){%>
103 | "vue-server-renderer": "^2.5.17",
104 | "vue-skeleton-webpack-plugin": "^1.2.2",<%}%>
105 | "vue-style-loader": "^3.0.1",
106 | "vue-template-compiler": "^2.5.2",
107 | "webpack": "^3.6.0",
108 | "webpack-bundle-analyzer": "^2.9.0",
109 | "webpack-dev-server": "^2.9.1",
110 | "webpack-merge": "^4.1.0"
111 | },
112 | "engines": {
113 | "node": ">= 6.0.0",
114 | "npm": ">= 3.0.0"
115 | },
116 | "browserslist": [
117 | "> 1%",
118 | "last 2 versions",
119 | "not ie <= 8",
120 | "iOS >= 7",
121 | "Firefox >= 20",
122 | "Android > 3.2"
123 | ]
124 | }
125 |
--------------------------------------------------------------------------------
/generators/app/templates/README.md:
--------------------------------------------------------------------------------
1 | # easy-vue
2 |
3 | > 多功能vue搬砖器
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | ```base
9 | yo easy-vue 一键生成可配置项目
10 | # install dependencies
11 | npm install or yarn install
12 |
13 | # 生成骨架屏(仅需要运行一次!)
14 | npm run skeleton
15 |
16 | # 生成开发环境下dll
17 | npm run dll:dev
18 |
19 | # 生成生产环境下dll
20 | npm run dll:build
21 |
22 | # eslint 代码检测
23 | npm run eslint
24 |
25 | # eslint 代码修复
26 | npm run eslint:fix
27 |
28 | # 代码格式化 (多人协作不建议使用,git commit 自动美化 eslint:fix自己修改部分的代码)
29 | npm run prettier
30 |
31 | #生成代码文档(jsdoc格式注释代码)
32 | npm run jsdoc
33 |
34 | # serve with hot reload at localhost:8080(自动 dll开发环境代码,并insert到html模板)
35 | npm run dev or npm run start
36 |
37 | # 测试环境
38 | npm run dev:test
39 |
40 | # rebuild钩子生成盛传环境dll 并eslint 代码
41 | npm run prebuild
42 |
43 | # build for production with minification(自动 dll生成环境代码,并insert到html模板已配置好publicPath)
44 | npm run build
45 |
46 | # build for production and view the bundle analyzer report
47 | npm run build --report
48 |
49 | #配置 publicPath imagePublicPath 或修改 config/index.js
50 | yo easy-vue:imagePublicPath path...
51 | yo easy-vue:publicPath path...
52 |
53 | # 一键生成页面
54 | yo easy-vue:page pageName 一键生成page
55 | yo easy-vue:mpage pageName 一键生成mutil-page(if you choose MPA)
56 | ```
57 | ## 功能
58 |
59 |
60 | ```
61 | 1. 支持可选reset.css normalize.css
62 | 2. 支持可选 rem布局 or vw布局
63 | 3. 等比例宽高容器 一像素边框等移动端解决方案
64 | 4. 支持可选less sass css预处理器
65 | 5. 动态加载路由,以及自动注入组件
66 | 6. 预渲染骨架屏
67 | 7. 按需(按照指定的浏览器环境所需)引入polyfill
68 | 8. 提供vue 插件alert demo写法
69 | 9. axios init配置
70 | 10. vuex init配置
71 | 11. vue-router两种模式 history 上线配置base url 填坑
72 | 12. 上线build 自动压缩图片
73 | 13. 重写image publicPath
74 | 14. 跨域反向代理案例
75 | 15. 单元测试和e2e todo
76 | 16. npm/yarn/bower...
77 | ```
78 |
79 | **0.1.4**
80 |
81 | 增加多页面应用
82 |
83 | **0.1.8**
84 |
85 | 增加一键生成多页面应用
86 |
87 | **0.2.0**
88 |
89 | 增加jsdoc配置 自动生成说明文档 增加对.vue文件的文档解析 jsdoc jsdoc-vue
90 |
91 | **0.2.1**
92 |
93 | 1. 增加代码检测工作流 prettier统一代码格式 precommit自动美化格式以及修复代码 lint-staged
94 | 2. 多人写作避免代码冲突,渐进式lint代码
95 | 3. 如果想要启用官方推荐的standard 可在.eslintrc.js中开启
96 |
97 | **0.2.2**
98 |
99 | 开启可配置dns预解析
100 |
101 | **0.2.3**
102 |
103 | 开启动态链接库dll并自动插入到模板中新增插件 DllPlugin,DllReferencePlugin,html-webpack-include-assets-plugin,cross-env
104 | 动态链接库修改在config/dll.lib.dependencies.js 默认只用了vue,vue-router
105 |
106 | **0.3.0**
107 |
108 | 实战之后的优化以及埋坑
109 |
110 | 1. css打包大小优化
111 | 2. 常用css方案(渐变兼容IE9 一像素边框 二倍图三倍图 iphoneX适配 等)
112 | 3. axios配置优化
113 | 4. 增加常见组件库 插件库 工具库
114 | ps: 非常棒的preload prefetch and prepack 相关插件不支持webpack3.X sad💔...
115 |
116 | **0.3.3**
117 |
118 | 1. 增加测试环境:开发环境接口 -> **mock**,测试环境走 ->**proxy**,生产环境直接打包线上全路径
119 | 2. 增加eventBus事件总线,挂载vue 全局调用
120 | 3. 修改loading插件样式
121 | 4. 请求增加超时提示,超时时间为10s
122 | 5. vw布局插件升级,支持排除node_momdules插件包,rem布局暂不支持可换插件postcss-px2rem-exclude or px2rem-exclude
123 |
124 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
125 |
126 | ## 目录结构
127 |
128 | ```
129 | .
130 | ├── build // 启动文件
131 | │ ├── build
132 | │ ├── check-versions.js
133 | │ ├── logo.png
134 | │ ├── commit-css-webpack-plugin.js //骨架屏相关插件
135 | │ ├── utils.js
136 | │ ├── vue-loader.conf.js
137 | │ ├── webpack.base.conf.js
138 | │ ├── webpack.dev.conf.js
139 | │ ├── webpack.prod.conf.js
140 | │ ├── webpack.test.conf.js
141 | │ ├── webpack.dll.conf.js //dll动态连接库
142 | │ ├── webpack.skeleton.conf.js //生成骨架屏
143 | ├── config // 项目环境配置
144 | │ ├── index.js // 入口
145 | │ ├── dll.libs.dependencies.js // dll所需库配置
146 | │ ├── dev.env.js // 开发环境配置
147 | │ ├── prod.env.js // 生成环境配置
148 | │ ├── test.env.js // 测试环境配置
149 | ├── dist // 上线打包
150 | │ ├── modules // 多页面
151 | │ ├── static
152 | │ │ ├── css
153 | │ │ ├── js
154 | │ │ └── libs //动态链接库文件
155 | ├── jsdoc // jsdoc 注释自动生成文档
156 | ├── src // 源码目录
157 | │ ├── assets
158 | │ ├── components
159 | │ ├── config
160 | │ │ ├── apis.js //封装接口
161 | │ │ ├── axiosConfig.js //配置axios
162 | │ │ ├── env.js //根据环境配置 切换接口baseURL && history模式路由配置
163 | │ ├── mixins
164 | │ ├── modules //多页面
165 | │ ├── pages
166 | │ ├── plugin //手写vue插件
167 | │ ├── filters //过滤器
168 | │ ├── direction //directions
169 | │ ├── router
170 | │ ├── store // 初始化vuex
171 | │ ├── eventBus // 事件总线
172 | │ ├── utils
173 | │ ├── APP.vue
174 | │ ├── mian.js
175 | │ ├── skeleton.entry.js //骨架屏配置
176 | ├── static
177 | ├── .babelrc
178 | ├── .editorconfig
179 | ├── eslintrc.js
180 | ├── .eslintignore
181 | ├── .gitignore
182 | ├── postcssrc.js
183 | ├── index.html
184 | ├── jsdoc.cong.json //jsdoc配置文件
185 | ├── .index
186 | ├── package.json
187 | ├── package-lock.json
188 | └── README.md
189 | ```
190 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/animation.css:
--------------------------------------------------------------------------------
1 | /*// fade*/
2 | /*.c-mask {
3 | position: fixed;
4 | top: 0;
5 | left: 0;
6 | bottom: 0;
7 | right: 0;
8 | height: 100%;
9 | background: rgba(0, 0, 0, .7);
10 | }*/
11 | /*// vue钩子动画*/
12 | .c-fade-enter-active, .c-fade-leave-active {
13 | transition: opacity .5s;
14 | }
15 | .c-fade-enter, .c-fade-leave-to {
16 | opacity: 0;
17 | }
18 |
19 | .c-fadedown-enter-active, .c-fadedown-leave-active {
20 | transform: translateY(0);
21 | transition: all .6s ease-out;
22 | }
23 | .c-fadedown-enter, .c-fadedown-leave-to {
24 | opacity: 0;
25 | transform: translateY(-100px);
26 | }
27 | .c-fademove-enter-active, .c-fademove-leave-active {
28 | transform: translate(-50%, -50%)!important;
29 | transition: all .6s ease-out;
30 | }
31 | .c-fademove-enter, .c-fademove-leave-to {
32 | opacity: 0;
33 | transform: translate(-50%, -45%)!important;
34 | }
35 | .c-zoom-enter-active {
36 | animation: zoomInUp .5s;
37 | }
38 |
39 | .c-zoom-leave-active {
40 | animation: zoomInDown .5s reverse;
41 | }
42 |
43 | .c-bounce-enter-active {
44 | animation: bounceInUp 1s ;
45 | }
46 |
47 | .c-bounce-leave-active {
48 | animation: bounceInUp .8s reverse;
49 | }
50 |
51 |
52 | .c-zoom {
53 | animation: zoomIn 4.15s infinite;
54 | }
55 | .c-zoom2 {
56 | animation: zoomIn3 1s linear infinite ;
57 | }
58 | .c-translateY1 {
59 | animation: translateY1 4.15s linear 1.2s infinite reverse ;
60 | }
61 | .c-translateY2 {
62 | animation: translateY2 4.15s linear 0.9s infinite reverse ;
63 | }
64 | .c-translateY3 {
65 | animation: translateY3 4.15s linear 0.3s infinite reverse ;
66 | }
67 | .c-translateY4 {
68 | animation: translateY3 4.15s linear 2s infinite reverse ;
69 | }
70 |
71 |
72 | .c-bounceinup {
73 | animation: bounceInUp .8s;
74 | }
75 |
76 | .c-flipInY {
77 | animation: flipInY .8s .1s;
78 | }
79 | .c-flipInY-1 {
80 | animation: flipInY .8s .2s;
81 | }
82 | .c-flipInY-2 {
83 | animation: flipInY-2 .8s .4s;
84 | }
85 | .c-flipInY-3 {
86 | animation: flipInY .8s .6s;
87 | }
88 | .c-flipInY-4 {
89 | animation: flipInY .8s .8s;
90 | }
91 | .c-flipInY-1 {
92 | animation: flipInY .8s .5s;
93 | }
94 |
95 | @keyframes zoomIn {
96 | from {
97 | transform: scale(.9);
98 | }
99 |
100 | 50% {
101 | transform: scale(1.1);
102 | }
103 |
104 | 100% {
105 | transform: scale(.9);
106 | }
107 | }
108 | @keyframes zoomIn3 {
109 | from {
110 | transform: scale(.85);
111 | }
112 |
113 | 50% {
114 | transform: scale(1);
115 | }
116 |
117 | 100% {
118 | transform: scale(.85);
119 | }
120 | }
121 |
122 | @keyframes translateY1 {
123 | from {
124 | transform: translateY(0);
125 | }
126 |
127 | 25% {
128 | transform: translateY(5px);
129 | }
130 | 50% {
131 | transform: translateY(0px);
132 | }
133 | 75% {
134 | transform: translateY(-5px);
135 | }
136 | 100% {
137 | transform: translateY(0);
138 | }
139 | }
140 | @keyframes translateY2 {
141 | from {
142 | transform: translateY(0);
143 | }
144 |
145 | 25% {
146 | transform: translateY(8px);
147 | }
148 | 50% {
149 | transform: translateY(0px);
150 | }
151 | 75% {
152 | transform: translateY(-8px);
153 | }
154 | 100% {
155 | transform: translateY(0);
156 | }
157 | }
158 | @keyframes translateY3 {
159 | from {
160 | transform: translateX(-50%) translateY(0);
161 | }
162 |
163 | 25% {
164 | transform: translateX(-50%) translateY(10px);
165 | }
166 | 50% {
167 | transform: translateX(-50%) translateY(0px);
168 | }
169 | 75% {
170 | transform: translateX(-50%) translateY(-10px);
171 | }
172 | 100% {
173 | transform: translateX(-50%) translateY(0);
174 | }
175 | }
176 |
177 |
178 | @keyframes zoomInUp {
179 | from {
180 | opacity: 0;
181 | transform: translate(-50%,-50%) scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
182 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
183 | }
184 |
185 | 60% {
186 | opacity: 1;
187 | transform: translate(-50%,-50%) scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
188 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
189 | }
190 | }
191 |
192 | @keyframes zoomInDown {
193 | from {
194 | opacity: 0;
195 | transform: translate(-50%,-50%) scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
196 | animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
197 | }
198 |
199 | 60% {
200 | opacity: 1;
201 | transform: translate(-50%,-50%) scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
202 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
203 | }
204 | }
205 |
206 | @keyframes bounceInUp {
207 |
208 | from {
209 | opacity: 0;
210 | transform: translate3d(-50%, 3000px, 0);
211 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
212 |
213 | }
214 |
215 | 60% {
216 | opacity: 1;
217 | transform: translate3d(-50%, -20px, 0);
218 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
219 |
220 | }
221 |
222 | 75% {
223 | transform: translate3d(-50%, 10px, 0);
224 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
225 |
226 | }
227 |
228 | 90% {
229 | transform: translate3d(-50%, -5px, 0);
230 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
231 |
232 | }
233 |
234 | to {
235 | transform: translate3d(-50%, 0, 0);
236 | animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
237 |
238 | }
239 | }
240 |
241 |
242 | @keyframes flipInY-2 {
243 | from {
244 | transform: translateX(-50%) perspective(400px) rotate3d(0, 1, 0, 90deg);
245 | animation-timing-function: ease-in;
246 | opacity: 0;
247 | }
248 |
249 | 40% {
250 | transform: translateX(-50%) perspective(400px) rotate3d(0, 1, 0, -20deg);
251 | animation-timing-function: ease-in;
252 | }
253 |
254 | 60% {
255 | transform: translateX(-50%) perspective(400px) rotate3d(0, 1, 0, 10deg);
256 | opacity: 1;
257 | }
258 |
259 | 80% {
260 | transform: translateX(-50%) perspective(400px) rotate3d(0, 1, 0, -5deg);
261 | }
262 |
263 | to {
264 | transform: translateX(-50%) perspective(400px);
265 | }
266 | }
267 |
268 | @keyframes flipInY {
269 | from {
270 | transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
271 | animation-timing-function: ease-in;
272 | opacity: 0;
273 | }
274 |
275 | 40% {
276 | transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
277 | animation-timing-function: ease-in;
278 | }
279 |
280 | 60% {
281 | transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
282 | opacity: 1;
283 | }
284 |
285 | 80% {
286 | transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
287 | }
288 |
289 | to {
290 | transform: perspective(400px);
291 | }
292 | }
293 |
294 |
--------------------------------------------------------------------------------
/generators/app/templates/build/_webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13 | const PurgecssPlugin = require('purgecss-webpack-plugin')//净化
14 | const glob = require('glob-all')
15 | // skeleton
16 | // const SkeletonWebpackPlugin = require('vue-skeleton-webpack-plugin')
17 | // const OmmitCSSPlugin = require('./ommit-css-webpack-plugin')
18 | const env = require('../config/prod.env')
19 | <% if(projectType =='MPA'){ %>
20 | // 多页面配置
21 | var glob = require('glob');
22 | var htmls = glob.sync('./src/modules/**/*.html').map(function (item) {
23 | return new HtmlWebpackPlugin({
24 | filename: './' + item.slice(6), // './modules/xx/xx.html'
25 | template: item, // './src/modules/**/*.html' 模板位置
26 | inject: true,
27 | chunks:[item.slice(6, -5),'vendor','manifest'] // '对应entry'
28 | });
29 | });<% }%>
30 | const webpackConfig = merge(baseWebpackConfig, {
31 | module: {
32 | rules: utils.styleLoaders({
33 | sourceMap: config.build.productionSourceMap,
34 | extract: true,
35 | usePostCSS: true
36 | })
37 | },
38 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
39 | output: {
40 | path: config.build.assetsRoot,
41 | //版本号由rd来控制 故去掉chunkhash
42 | // filename: utils.assetsPath('js/[name].[chunkhash].js'),
43 | filename: utils.assetsPath('js/[name].js'),
44 | chunkFilename: utils.assetsPath('js/[name].[chunkhash:7].js')
45 | },
46 | plugins: [
47 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
48 | new webpack.DefinePlugin({
49 | 'process.env': env
50 | }),
51 | new UglifyJsPlugin({
52 | uglifyOptions: {
53 | compress: {
54 | warnings: false,
55 | drop_console: true,//删除所有的 `console` 语句,可以兼容ie浏览器
56 | }
57 | },
58 | sourceMap: config.build.productionSourceMap,
59 | parallel: true
60 | }),
61 | // extract css into its own file
62 | new ExtractTextPlugin({
63 | filename: utils.assetsPath('css/[name].css'),
64 | // Setting the following option to `false` will not extract CSS from codesplit chunks.
65 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
66 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
67 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
68 | // publicPath: config.build.cssPublicPath,
69 | allChunks: true,
70 | }),
71 |
72 | // skeleton
73 | // new SkeletonWebpackPlugin({
74 | // webpackConfig: require('./webpack.skeleton.conf'),
75 | // quiet: true
76 | // }),
77 | // new OmmitCSSPlugin(),
78 |
79 | // Compress extracted CSS. We are using this plugin so that possible
80 | // duplicated CSS from different components can be deduped.
81 | new OptimizeCSSPlugin({
82 | cssProcessorOptions: config.build.productionSourceMap
83 | ? { safe: true, map: { inline: false } }
84 | : { safe: true }
85 | }),
86 | // generate dist index.html with correct asset hash for caching.
87 | // you can customize output by editing /index.html
88 | // see https://github.com/ampedandwired/html-webpack-plugin
89 | <% if(projectType =='SPA'){ %>
90 | new HtmlWebpackPlugin({
91 | filename: config.build.index,
92 | template: 'index.html',
93 | inject: true,
94 | minify: {
95 | removeComments: true,
96 | collapseWhitespace: true,
97 | removeAttributeQuotes: true
98 | // more options:
99 | // https://github.com/kangax/html-minifier#options-quick-reference
100 | },
101 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
102 | chunksSortMode: 'dependency'
103 | }),<%}%>
104 | // keep module.id stable when vendor modules does not change
105 | new webpack.HashedModuleIdsPlugin(),
106 | // enable scope hoisting
107 | new webpack.optimize.ModuleConcatenationPlugin(),
108 | // split vendor js into its own file
109 | new webpack.optimize.CommonsChunkPlugin({
110 | name: 'vendor',
111 | minChunks (module) {
112 | // any required modules inside node_modules are extracted to vendor
113 | return (
114 | module.resource &&
115 | /\.js$/.test(module.resource) &&
116 | module.resource.indexOf(
117 | path.join(__dirname, '../node_modules')
118 | ) === 0
119 | )
120 | }
121 | }),
122 | // extract webpack runtime and module manifest to its own file in order to
123 | // prevent vendor hash from being updated whenever app bundle is updated
124 | new webpack.optimize.CommonsChunkPlugin({
125 | name: 'manifest',
126 | minChunks: Infinity
127 | }),
128 | // This instance extracts shared chunks from code splitted chunks and bundles them
129 | // in a separate chunk, similar to the vendor chunk
130 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
131 | new webpack.optimize.CommonsChunkPlugin({
132 | name: 'app',
133 | async: 'vendor-async',
134 | children: true,
135 | minChunks: 3
136 | }),
137 | // css tree shake 净化
138 | new PurgecssPlugin({
139 | paths: glob.sync(config.build.purgecssPath)
140 | }),
141 | // copy custom static assets
142 | new CopyWebpackPlugin([
143 | {
144 | from: path.resolve(__dirname, '../static'),
145 | to: config.build.assetsSubDirectory,
146 | ignore: ['.*']
147 | }
148 | ])
149 | ]<% if(projectType =='MPA'){ %>.concat(htmls)<%}%>
150 | })
151 |
152 | if (config.build.productionGzip) {
153 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
154 |
155 | webpackConfig.plugins.push(
156 | new CompressionWebpackPlugin({
157 | asset: '[path].gz[query]',
158 | algorithm: 'gzip',
159 | test: new RegExp(
160 | '\\.(' +
161 | config.build.productionGzipExtensions.join('|') +
162 | ')$'
163 | ),
164 | threshold: 10240,
165 | minRatio: 0.8
166 | })
167 | )
168 | }
169 |
170 | if (config.build.bundleAnalyzerReport) {
171 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
172 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
173 | }
174 |
175 | module.exports = webpackConfig
176 |
--------------------------------------------------------------------------------
/generators/app/templates/src/assets/css/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15; /* 1 */
13 | -webkit-text-size-adjust: 100%; /* 2 */
14 | }
15 |
16 | /* Sections
17 | ========================================================================== */
18 |
19 | /**
20 | * Remove the margin in all browsers.
21 | */
22 |
23 | body {
24 | margin: 0;
25 | }
26 |
27 | /**
28 | * Render the `main` element consistently in IE.
29 | */
30 |
31 | main {
32 | display: block;
33 | }
34 |
35 | /**
36 | * Correct the font size and margin on `h1` elements within `section` and
37 | * `article` contexts in Chrome, Firefox, and Safari.
38 | */
39 |
40 | h1 {
41 | font-size: 2em;
42 | margin: 0.67em 0;
43 | }
44 |
45 | /* Grouping content
46 | ========================================================================== */
47 |
48 | /**
49 | * 1. Add the correct box sizing in Firefox.
50 | * 2. Show the overflow in Edge and IE.
51 | */
52 |
53 | hr {
54 | box-sizing: content-box; /* 1 */
55 | height: 0; /* 1 */
56 | overflow: visible; /* 2 */
57 | }
58 |
59 | /**
60 | * 1. Correct the inheritance and scaling of font size in all browsers.
61 | * 2. Correct the odd `em` font sizing in all browsers.
62 | */
63 |
64 | pre {
65 | font-family: monospace, monospace; /* 1 */
66 | font-size: 1em; /* 2 */
67 | }
68 |
69 | /* Text-level semantics
70 | ========================================================================== */
71 |
72 | /**
73 | * Remove the gray background on active links in IE 10.
74 | */
75 |
76 | a {
77 | background-color: transparent;
78 | }
79 |
80 | /**
81 | * 1. Remove the bottom border in Chrome 57-
82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
83 | */
84 |
85 | abbr[title] {
86 | border-bottom: none; /* 1 */
87 | text-decoration: underline; /* 2 */
88 | text-decoration: underline dotted; /* 2 */
89 | }
90 |
91 | /**
92 | * Add the correct font weight in Chrome, Edge, and Safari.
93 | */
94 |
95 | b,
96 | strong {
97 | font-weight: bolder;
98 | }
99 |
100 | /**
101 | * 1. Correct the inheritance and scaling of font size in all browsers.
102 | * 2. Correct the odd `em` font sizing in all browsers.
103 | */
104 |
105 | code,
106 | kbd,
107 | samp {
108 | font-family: monospace, monospace; /* 1 */
109 | font-size: 1em; /* 2 */
110 | }
111 |
112 | /**
113 | * Add the correct font size in all browsers.
114 | */
115 |
116 | small {
117 | font-size: 80%;
118 | }
119 |
120 | /**
121 | * Prevent `sub` and `sup` elements from affecting the line height in
122 | * all browsers.
123 | */
124 |
125 | sub,
126 | sup {
127 | font-size: 75%;
128 | line-height: 0;
129 | position: relative;
130 | vertical-align: baseline;
131 | }
132 |
133 | sub {
134 | bottom: -0.25em;
135 | }
136 |
137 | sup {
138 | top: -0.5em;
139 | }
140 |
141 | /* Embedded content
142 | ========================================================================== */
143 |
144 | /**
145 | * Remove the border on images inside links in IE 10.
146 | */
147 |
148 | img {
149 | border-style: none;
150 | }
151 |
152 | /* Forms
153 | ========================================================================== */
154 |
155 | /**
156 | * 1. Change the font styles in all browsers.
157 | * 2. Remove the margin in Firefox and Safari.
158 | */
159 |
160 | button,
161 | input,
162 | optgroup,
163 | select,
164 | textarea {
165 | font-family: inherit; /* 1 */
166 | font-size: 100%; /* 1 */
167 | line-height: 1.15; /* 1 */
168 | margin: 0; /* 2 */
169 | }
170 |
171 | /**
172 | * Show the overflow in IE.
173 | * 1. Show the overflow in Edge.
174 | */
175 |
176 | button,
177 | input { /* 1 */
178 | overflow: visible;
179 | }
180 |
181 | /**
182 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
183 | * 1. Remove the inheritance of text transform in Firefox.
184 | */
185 |
186 | button,
187 | select { /* 1 */
188 | text-transform: none;
189 | }
190 |
191 | /**
192 | * Correct the inability to style clickable types in iOS and Safari.
193 | */
194 |
195 | button,
196 | [type="button"],
197 | [type="reset"],
198 | [type="submit"] {
199 | -webkit-appearance: button;
200 | }
201 |
202 | /**
203 | * Remove the inner border and padding in Firefox.
204 | */
205 |
206 | button::-moz-focus-inner,
207 | [type="button"]::-moz-focus-inner,
208 | [type="reset"]::-moz-focus-inner,
209 | [type="submit"]::-moz-focus-inner {
210 | border-style: none;
211 | padding: 0;
212 | }
213 |
214 | /**
215 | * Restore the focus styles unset by the previous rule.
216 | */
217 |
218 | button:-moz-focusring,
219 | [type="button"]:-moz-focusring,
220 | [type="reset"]:-moz-focusring,
221 | [type="submit"]:-moz-focusring {
222 | outline: 1px dotted ButtonText;
223 | }
224 |
225 | /**
226 | * Correct the padding in Firefox.
227 | */
228 |
229 | fieldset {
230 | padding: 0.35em 0.75em 0.625em;
231 | }
232 |
233 | /**
234 | * 1. Correct the text wrapping in Edge and IE.
235 | * 2. Correct the color inheritance from `fieldset` elements in IE.
236 | * 3. Remove the padding so developers are not caught out when they zero out
237 | * `fieldset` elements in all browsers.
238 | */
239 |
240 | legend {
241 | box-sizing: border-box; /* 1 */
242 | color: inherit; /* 2 */
243 | display: table; /* 1 */
244 | max-width: 100%; /* 1 */
245 | padding: 0; /* 3 */
246 | white-space: normal; /* 1 */
247 | }
248 |
249 | /**
250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
251 | */
252 |
253 | progress {
254 | vertical-align: baseline;
255 | }
256 |
257 | /**
258 | * Remove the default vertical scrollbar in IE 10+.
259 | */
260 |
261 | textarea {
262 | overflow: auto;
263 | }
264 |
265 | /**
266 | * 1. Add the correct box sizing in IE 10.
267 | * 2. Remove the padding in IE 10.
268 | */
269 |
270 | [type="checkbox"],
271 | [type="radio"] {
272 | box-sizing: border-box; /* 1 */
273 | padding: 0; /* 2 */
274 | }
275 |
276 | /**
277 | * Correct the cursor style of increment and decrement buttons in Chrome.
278 | */
279 |
280 | [type="number"]::-webkit-inner-spin-button,
281 | [type="number"]::-webkit-outer-spin-button {
282 | height: auto;
283 | }
284 |
285 | /**
286 | * 1. Correct the odd appearance in Chrome and Safari.
287 | * 2. Correct the outline style in Safari.
288 | */
289 |
290 | [type="search"] {
291 | -webkit-appearance: textfield; /* 1 */
292 | outline-offset: -2px; /* 2 */
293 | }
294 |
295 | /**
296 | * Remove the inner padding in Chrome and Safari on macOS.
297 | */
298 |
299 | [type="search"]::-webkit-search-decoration {
300 | -webkit-appearance: none;
301 | }
302 |
303 | /**
304 | * 1. Correct the inability to style clickable types in iOS and Safari.
305 | * 2. Change font properties to `inherit` in Safari.
306 | */
307 |
308 | ::-webkit-file-upload-button {
309 | -webkit-appearance: button; /* 1 */
310 | font: inherit; /* 2 */
311 | }
312 |
313 | /* Interactive
314 | ========================================================================== */
315 |
316 | /*
317 | * Add the correct display in Edge, IE 10+, and Firefox.
318 | */
319 |
320 | details {
321 | display: block;
322 | }
323 |
324 | /*
325 | * Add the correct display in all browsers.
326 | */
327 |
328 | summary {
329 | display: list-item;
330 | }
331 |
332 | /* Misc
333 | ========================================================================== */
334 |
335 | /**
336 | * Add the correct display in IE 10+.
337 | */
338 |
339 | template {
340 | display: none;
341 | }
342 |
343 | /**
344 | * Add the correct display in IE 10.
345 | */
346 |
347 | [hidden] {
348 | display: none;
349 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # generator-easy-vue
2 | > a generator for a super vue
3 |
4 | > 此项目为开箱即用的vue项目生成器,几乎项目中用到的所有东西都一配置好,让你写代码如丝滑般顺滑~
5 |
6 | ## 功能
7 |
8 | ```
9 | 1. 支持可选reset.css/normalize.css
10 | 2. 支持可选 rem布局/vw布局
11 | 3. 等比例宽高容器 一像素边框等移动端解决方案
12 | 4. 支持可选less sass css预处理器
13 | 5. 动态加载路由
14 | 6. 自动注入全局组件
15 | 7. 预渲染骨架屏
16 | 8. 按需(按照指定的浏览器环境所需)引入polyfill
17 | 9. axios 简易配置 拦截器配置 全局拦截 超时提示等
18 | 10. vuex 简易配置
19 | 11. vue-router简易配置
20 | 12. build 自动压缩图片
21 | 13. 重写image publicPath
22 | 14. 跨域反向代理案例
23 | 15. 简易路由动画配置
24 | 16. 常用组件库 插件库(alert confirm loading toast) 工具库
25 | 17. 多页面应用以及一键生成页面命令
26 | 18. 注释自动生成说明文档配置
27 | 19. 增加代码检测工作流 precommit自动美化格式以及修复代码,多人写作避免代码冲突,渐进式lint代码
28 | 20. dns预加载配置
29 | 21. 动态链接库dll配置
30 | 22. css打包大小优化配置 设置全局css等
31 | 23. postcss插件配置
32 | 24. css的tree shake配置
33 | ```
34 |
35 | **0.1.4**
36 |
37 | 增加多页面应用
38 |
39 | **0.1.8**
40 |
41 | 增加一键生成多页面应用
42 |
43 | **0.2.0**
44 |
45 | 增加jsdoc配置 自动生成说明文档 增加对.vue文件的文档解析 jsdoc jsdoc-vue
46 |
47 | **0.2.1**
48 |
49 | 1. 增加代码检测工作流 prettier统一代码格式 precommit自动美化格式以及修复代码 lint-staged
50 | 2. 多人写作避免代码冲突,渐进式lint代码
51 | 3. 如果想要启用官方推荐的standard 可在.eslintrc.js中开启
52 |
53 | **0.2.2**
54 |
55 | 开启可配置dns预解析
56 |
57 | **0.2.3**
58 |
59 | 开启动态链接库dll并自动插入到模板中新增插件 DllPlugin,DllReferencePlugin,html-webpack-include-assets-plugin,cross-env
60 | 动态链接库修改在config/dll.lib.dependencies.js 默认只用了vue,vue-router
61 |
62 | **0.3.0**
63 |
64 | 实战之后的优化以及埋坑
65 |
66 | 1. css打包大小优化
67 | 2. 常用css方案(渐变兼容IE9 一像素边框 二倍图三倍图 iphoneX适配 等)
68 | 3. axios配置优化
69 | 4. 增加常见组件库 插件库 工具库
70 | ps: 非常棒的preload prefetch and JavaScript源代码优化工具prepack 相关插件不支持webpack3.X 💔 后期考虑升级webpack4+ or在vue-cli3基础上重新配置...
71 |
72 | **0.3.3**
73 |
74 | 1. 增加测试环境:开发环境接口 -> **mock**,测试环境走 ->**proxy**,生产环境直接打包线上全路径
75 | 2. 增加eventBus事件总线,挂载vue 全局调用
76 | 3. 修改loading插件样式
77 | 4. 请求增加超时提示,超时时间为10s
78 | 5. vw布局插件升级,支持排除node_momdules插件包,rem布局暂不支持。可换插件postcss-px2rem-exclude or px2rem-exclude
79 |
80 | **0.3.9**
81 |
82 | 路由动画 router zIndex控制层级
83 |
84 | **0.4.0**
85 |
86 | - css tree shake净化css, config/index配置purgecssPath
87 | - postcss插件替换 postcss-preset-env替代cssnext 默认stage:2
88 |
89 | > 初始化项目
90 |
91 |
92 |
93 | > 初始化骨架屏
94 |
95 |
96 |
97 | > 自动生成页面
98 |
99 |
100 |
101 | > 骨架屏效果
102 |
103 |
104 |
105 | ## Installation
106 |
107 | ```bash
108 | npm install -g yo
109 | npm install -g generator-easy-vue
110 | ```
111 |
112 | Then generate your new project:
113 |
114 | ```base
115 | yo easy-vue 一键生成可配置项目
116 | # install dependencies
117 | npm install or yarn install
118 |
119 | # 生成骨架屏(仅需要运行一次!)
120 | npm run skeleton
121 |
122 | # 生成开发环境下dll
123 | npm run dll:dev
124 |
125 | # 生成生产环境下dll
126 | npm run dll:build
127 |
128 | # eslint 代码检测
129 | npm run eslint
130 |
131 | # eslint 代码修复
132 | npm run eslint:fix
133 |
134 | # 代码格式化 (多人协作不建议使用,git commit 自动美化 eslint:fix自己修改部分的代码)
135 | npm run prettier
136 |
137 | #生成代码文档(jsdoc格式注释代码)
138 | npm run jsdoc
139 |
140 | # serve with hot reload at localhost:8080(自动 dll开发环境代码,并insert到html模板)
141 | npm run dev or npm run start
142 |
143 | # rebuild钩子生成盛传环境dll 并eslint 代码
144 | npm run prebuild
145 |
146 | # build for production with minification(自动 dll生成环境代码,并insert到html模板已配置好publicPath)
147 | npm run build
148 |
149 | # build for production and view the bundle analyzer report
150 | npm run build --report
151 |
152 | #配置 publicPath imagePublicPath 或修改 config/index.js
153 | yo easy-vue:imagePublicPath path...
154 | yo easy-vue:publicPath path...
155 |
156 | # 一键生成页面
157 | yo easy-vue:page pageName 一键生成page
158 | yo easy-vue:mpage pageName 一键生成mutil-page(if you choose MPA)
159 | ```
160 |
161 |
162 | ## 项目相关依赖
163 |
164 | > dependencies
165 |
166 | ```
167 | fastclick
168 | amfe-flexible
169 | axios
170 | vuex
171 | vue
172 | vue-router
173 | ```
174 | > devDependencies
175 |
176 | ```
177 | less
178 | less-loader
179 | node-sass
180 | sass-loader
181 | postcss-pxtorem
182 | image-webpack-plugin
183 | vue-server-renderer
184 | vue-skeleton-webpack-plugin
185 | postcss-aspect-ratio-mini
186 | postcss-px-to-viewport
187 | postcss-write-svg
188 | postcss-cssnext
189 | style-resources-loader
190 | postcss-viewport-units 已弃用
191 | style
192 | cssnano
193 | cssnano-preset-advanced
194 | babel-eslint eslint eslint-config-standard eslint-friendly-formatter eslint-loader eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard eslint-plugin-vue
195 | lint-staged
196 | husky
197 | prettier
198 | jsdoc
199 | jsdoc-vue
200 | DllPlugin
201 | DllReferencePlugin
202 | html-webpack-include-assets-plugin
203 | cross-env
204 | ....
205 | ```
206 |
207 |
208 | ## 目录结构
209 |
210 | ```
211 | .
212 | ├── build // 启动文件
213 | │ ├── build
214 | │ ├── check-versions.js
215 | │ ├── logo.png
216 | │ ├── commit-css-webpack-plugin.js //骨架屏相关插件
217 | │ ├── utils.js
218 | │ ├── vue-loader.conf.js
219 | │ ├── webpack.base.conf.js
220 | │ ├── webpack.dev.conf.js
221 | │ ├── webpack.prod.conf.js
222 | │ ├── webpack.test.conf.js
223 | │ ├── webpack.dll.conf.js //dll动态连接库
224 | │ ├── webpack.skeleton.conf.js //生成骨架屏
225 | ├── config // 项目环境配置
226 | │ ├── index.js // 入口
227 | │ ├── dll.libs.dependencies.js // dll所需库配置
228 | │ ├── dev.env.js // 开发环境配置
229 | │ ├── prod.env.js // 生成环境配置
230 | │ ├── test.env.js // 测试环境配置
231 | ├── dist // 上线打包
232 | │ ├── modules // 多页面
233 | │ ├── static
234 | │ │ ├── css
235 | │ │ ├── js
236 | │ │ └── libs //动态链接库文件
237 | ├── jsdoc // jsdoc 注释自动生成文档
238 | ├── src // 源码目录
239 | │ ├── assets
240 | │ ├── components
241 | │ ├── config
242 | │ │ ├── apis.js //封装接口
243 | │ │ ├── axiosConfig.js //配置axios
244 | │ │ ├── env.js //根据环境配置 切换接口baseURL && history模式路由配置
245 | │ ├── mixins
246 | │ ├── modules //多页面
247 | │ ├── pages
248 | │ ├── plugin //手写vue插件
249 | │ ├── filters //过滤器
250 | │ ├── direction //directions
251 | │ ├── router
252 | │ ├── store // 初始化vuex
253 | │ ├── eventBus // 事件总线
254 | │ ├── utils
255 | │ ├── APP.vue
256 | │ ├── mian.js
257 | │ ├── skeleton.entry.js //骨架屏配置
258 | ├── static
259 | ├── .babelrc
260 | ├── .editorconfig
261 | ├── eslintrc.js
262 | ├── .eslintignore
263 | ├── .gitignore
264 | ├── postcssrc.js
265 | ├── index.html
266 | ├── jsdoc.cong.json //jsdoc配置文件
267 | ├── .index
268 | ├── package.json
269 | ├── package-lock.json
270 | └── README.md
271 | ```
272 |
273 |
274 | ## vue项目生成器
275 |
276 | > 地址[项目生成器](https://github.com/501981732/generator-easy-vue)
277 |
278 |
279 |
280 | ## License
281 |
282 | MIT © [wangmeng](https://github.com/501981732)
283 |
284 |
285 | [npm-image]: https://badge.fury.io/js/generator-easy-vue.svg
286 | [npm-url]: https://npmjs.org/package/generator-easy-vue
287 | [travis-image]: https://travis-ci.org/501981732/generator-easy-vue.svg?branch=master
288 | [travis-url]: https://travis-ci.org/501981732/generator-easy-vue
289 | [daviddm-image]: https://david-dm.org/501981732/generator-easy-vue.svg?theme=shields.io
290 | [daviddm-url]: https://david-dm.org/501981732/generator-easy-vue
291 | [coveralls-image]: https://coveralls.io/repos/501981732/generator-easy-vue/badge.svg
292 | [coveralls-url]: https://coveralls.io/r/501981732/generator-easy-vue
293 |
--------------------------------------------------------------------------------
/generators/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* eslint-disable */
3 | const Generator = require('yeoman-generator');
4 | const chalk = require('chalk');
5 | const yosay = require('yosay');
6 | const path = require('path');
7 | const util = require('util');
8 |
9 | /**
10 | * 生命周期
11 | *prompting - 接收用户输入阶段
12 | *configuring - 保存配置信息和文件
13 | *default - 自定义功能函数名称,如 method1
14 | *writing - 生成项目目录结构阶段
15 | *conflicts - 统一处理冲突,如要生成的文件已经存在是否覆盖等处理
16 | *install - 安装依赖阶段
17 | *end - 生成器结束阶段
18 | */
19 | module.exports = class extends Generator {
20 | // constructor(args,opts) {
21 | // super(args,opts)
22 | // this.appname = 'xxx'
23 | // }
24 | prompting() {
25 | this.log(
26 | yosay(`Welcome to the ${chalk.red('easy-vue')} generator! ${chalk.red('多功能搬砖器')}`)
27 | );
28 |
29 | const prompts = [{
30 | name: 'projectName', // 用户输入项标识,在获取用户输入值的时候用到
31 | message: 'your project name?', //给用户提示的信息
32 | // default: this.appname // 默认值
33 | default: path.basename(process.cwd()) // 默认值
34 | }, {
35 | type: 'text',
36 | name: 'author',
37 | message: 'Your name',
38 | default: this.user.git.name()
39 | }, {
40 | type: 'input',
41 | name: 'email',
42 | message: 'Your email',
43 | default: this.user.git.email()
44 | }, {
45 | name: 'projectType',
46 | type: 'list',
47 | message: 'Which type application do you want to build ?',
48 | choices: [{
49 | name: 'SPA',
50 | value: 'SPA',
51 | checked: true
52 | }, {
53 | name: 'MPA',
54 | value: 'MPA'
55 | }, ]
56 | }, {
57 | name: 'reset',
58 | type: 'list',
59 | message: 'Choose a way to reset your css',
60 | choices: [{
61 | name: 'reset.css',
62 | value: 'reset.css',
63 | checked: true
64 | }, {
65 | name: 'normalize.css',
66 | value: 'normalize.css'
67 | }, {
68 | name: 'none',
69 | value: 'none'
70 | }]
71 | }, {
72 | name: 'cssPrepeocessor',
73 | type: 'list',
74 | message: 'Choose a CSS preprocessor',
75 | choices: [{
76 | name: 'less',
77 | value: 'less',
78 | checked: true
79 | }, {
80 | name: 'sass',
81 | value: 'scss'
82 | }]
83 | }, {
84 | name: 'layout',
85 | type: 'list',
86 | message: 'Choose a layout scheme if you need a M project',
87 | choices: [{
88 | name: 'rem',
89 | value: 'rem',
90 | checked: true
91 | }, {
92 | name: 'vw',
93 | value: 'vw'
94 | }, {
95 | name: 'none',
96 | value: 'none'
97 | }]
98 | }, {
99 | type: 'confirm', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
100 | name: 'skeleton',
101 | message: 'Do you need a initialized skeleton ?',
102 | default: true
103 | }, {
104 | type: 'confirm', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
105 | name: 'vuex',
106 | message: 'Do you need a initialized vuex ?',
107 | default: true,
108 | store: true
109 | }, {
110 | type: 'confirm', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
111 | name: 'eslint',
112 | message: 'Use eslint and prettier to lint your code?',
113 | default: true,
114 | store: true
115 | }, {
116 | type: 'text', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
117 | name: 'imagePublicPath',
118 | message: 'Do you need a imagePublicPath ?',
119 | store: true //本地保留配置
120 | }, {
121 | type: 'input', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
122 | name: 'publicPath',
123 | message: 'Do you need a assetsPublicPath ?',
124 | store: true
125 | }, {
126 | type: 'input', // 非必填 默认text ‘confirm’ 是选择输入‘YES/NO’
127 | name: 'dns',
128 | message: 'If you need a dns prefetch,Please input the dns split by ","',
129 | store: true
130 | }, {
131 | name: 'installationMethod',
132 | type: 'list',
133 | message: 'Choose a way to install the package:',
134 | choices: [{
135 | name: 'yarn',
136 | value: 'yarn',
137 | checked: true
138 | }, {
139 | name: 'npm',
140 | value: 'npm'
141 | }, {
142 | name: 'no I install packages by myself',
143 | value: 'no'
144 | }]
145 | }];
146 |
147 | return this.prompt(prompts).then(props => {
148 | // To access props later use this.props.xxx;
149 | this.props = props;
150 | });
151 | }
152 |
153 | writing() {
154 | // this.templatePath 返回template目录下文件的地址
155 | // this.destinationPath 指定加工完成后文件的存放地址 一般指项目目录
156 | // this.fs.copy 把文件从一个目录复制到另一个目录,一般是从template目录复制到你所指定的项目目录,用于固定文件和可选文件(根据用户选择)
157 | // this.fs.copyTpl:和上面的函数作用一样,不过会事先经过模板引擎的处理,一般用来根据用户输入处理加工文件
158 | let target = [
159 | //需要加工的文件使用数组
160 | 'build/build.js',
161 | 'build/check-versions.js',
162 | 'build/logo.png',
163 | 'build/vue-loader.conf.js',
164 | 'config/dev.env.js',
165 | 'config/prod.env.js',
166 | 'src/assets/css/common.css',
167 | 'src/assets/css/animation.css',
168 | 'src/assets/js/.gitkeep',
169 | 'src/assets/img/',
170 | 'src/assets/logo.png',
171 | 'src/components/global.js',
172 | 'src/components/Alert.vue',
173 | 'src/components/Loading.vue',
174 | 'src/components/Toast.vue',
175 | 'src/components/Confirm.vue',
176 | 'src/config',
177 | 'src/directions/',
178 | 'src/filters/',
179 | 'src/mixins/',
180 | 'src/plugins/',
181 | 'src/router/',
182 | 'src/utils/',
183 | 'static/.gitkeep',
184 | '.babelrc',
185 | '.editorconfig',
186 | 'README.md',
187 | 'yarn.lock',
188 | 'jsdoc.conf.json',
189 | 'package-lock.json',
190 | 'build/webpack.dll.conf.js',
191 | 'CHANGELOG.md',
192 | 'config/dll.libs.dependencies.js',
193 | 'config/test.env.js',//增加测试环境
194 | 'src/eventBus',//增加事件总线
195 | ]
196 |
197 | // fix linux 添加隐藏文件
198 | target = [...target, ['_gitignore', '.gitignore'],
199 | ['_package.json', 'package.json'],
200 | ['_postcssrc.js', '.postcssrc.js'],
201 | ['config/_index.js', 'config/index.js'],
202 | ['_index.html', 'index.html'],
203 | // ['src/components/_x-alert.vue', 'src/components/x-alert.vue'],
204 | ['src/pages/_HelloWorld.vue', 'src/pages/HelloWorld.vue'],
205 | ['build/_webpack.base.conf.js', 'build/webpack.base.conf.js'],
206 | ['build/_webpack.dev.conf.js', 'build/webpack.dev.conf.js'],
207 | ['build/_webpack.prod.conf.js', 'build/webpack.prod.conf.js'],
208 | ['build/_webpack.test.conf.js', 'build/webpack.test.conf.js'],////增加测试环境
209 | ['build/_utils.js', 'build/utils.js', ],
210 | ]
211 | // 是否添加单元测试
212 | // this.props.test && target.push('test/index.spec.js')
213 | this.props.reset == 'reset.css' && target.push('src/assets/css/reset.css')
214 | this.props.reset == 'normalize.css' && target.push('src/assets/css/normalize.css')
215 | // less处理 全局引入
216 | this.props.cssPrepeocessor === 'less' && target.push('src/assets/css/vars.less','src/assets/css/mixins.less')
217 | this.props.layout == 'vw' && target.push('src/components/vwDemo.vue')
218 | this.props.vuex && target.push('src/store')
219 | this.props.skeleton && target.push('build/webpack.skeleton.conf.js',
220 | 'src/components/skeleton.vue',
221 | 'src/skeleton.entry.js',
222 | 'skeleton.js')
223 | // 配置多页面
224 | this.props.projectType == 'SPA' && target.push(['src/_main.js', 'src/main.js'], 'src/App.vue', )
225 | this.props.projectType == 'MPA' && target.push('src/modules/index/index.html', 'src/modules/index/index.vue', ['src/modules/index/_index.js', 'src/modules/index/index.js'])
226 | // eslint
227 | this.props.eslint && target.push('.eslintignore', '.eslintrc.js')
228 |
229 | // dns
230 | // if (this.props.dns) {
231 | // this.props.dnsArray = this.props.split(',')
232 | // } else {
233 | // this.props.dnsArray = []
234 | // }
235 |
236 | target.forEach(item => {
237 | let toFile, fromFile;
238 | if (Array.isArray(item)) {
239 | fromFile = item[0];
240 | toFile = item[1];
241 | this.fs.copyTpl(
242 | this.templatePath(fromFile),
243 | this.destinationPath(toFile),
244 | // 将配置参数带过去
245 | this.props
246 | );
247 | } else {
248 | fromFile = item;
249 | toFile = item;
250 | this.fs.copy(
251 | this.templatePath(fromFile),
252 | this.destinationPath(toFile),
253 | this.props
254 | );
255 | }
256 | })
257 | }
258 | install() {
259 | switch (this.props.installationMethod) {
260 | case 'npm':
261 | this.npmInstall();
262 | break;
263 | case 'yarn':
264 | this.yarnInstall();
265 | break;
266 | case 'bower':
267 | this.bowerInstall();
268 | break;
269 | default:
270 | break;
271 | }
272 |
273 | }
274 | end() {
275 | this.log(yosay(`${chalk.green('Now do something ')}${chalk.blue(' whatever you want!!')} `))
276 | }
277 | };
278 |
--------------------------------------------------------------------------------
/generators/app/templates/src/utils/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 平滑滚动顶部
3 | * @author wm
4 | * @DateTime 2018-09-29
5 | */
6 |
7 | const scrollToTop = () => {
8 | const c = document.documentElement.scrollTop || document.body.scrollTop;
9 | if (c > 0) {
10 | window.requestAnimationFrame(scrollToTop);
11 | window.scrollTo(0, c - c / 8);
12 | }
13 | };
14 | /**
15 | * 滚动
16 | * @Author wangmeng
17 | * @DateTime 2019-02-22
18 | * @param {object} element dom
19 | * @param {number} speed speed
20 | */
21 | const animateScroll = (element, speed) => {
22 | let rect = element.getBoundingClientRect();
23 | //获取元素相对窗口的top值,此处应加上窗口本身的偏移
24 | let top = window.pageYOffset + rect.top;
25 | let currentTop = 0;
26 | let requestId;
27 | //采用requestAnimationFrame,平滑动画
28 | function step(timestamp) {
29 | currentTop += speed;
30 | if (currentTop <= top) {
31 | window.scrollTo(0, currentTop);
32 | requestId = window.requestAnimationFrame(step);
33 | } else {
34 | window.cancelAnimationFrame(requestId);
35 | }
36 | }
37 | window.requestAnimationFrame(step);
38 | };
39 | /**
40 | * 验证邮箱
41 | * @author wm
42 | * @DateTime 2018-09-05
43 | * @param {string} str 验证的邮箱
44 | * @returns {boolean} 是否是邮箱
45 | */
46 | const validateEmail = str =>
47 | /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
48 | str
49 | );
50 |
51 | /**
52 | * 验证数字
53 | * @author wm
54 | * @DateTime 2018-09-05
55 | * @param {string} n 验证的数字
56 | * @returns {boolean} 是否是数据
57 | */
58 | const validateNumber = n =>
59 | !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
60 |
61 | /**
62 | * 验证电话
63 | * @author wm
64 | * @DateTime 2018-09-05
65 | * @param {string} n 验证的电话
66 | * @returns {boolean} 是否是电话号码
67 | */
68 |
69 | const validataPhone = n => /^[1][3,4,5,7,8,9][0-9]{9}$/.test(n);
70 |
71 | /**
72 | * 验证固定电话
73 | * @author wm
74 | * @DateTime 2018-09-05
75 | * @param {string} n 验证的固定电话
76 | * @returns {boolean} 是否是固定电话
77 | */
78 |
79 | const validataFixedLineTelephone = n => /\d{2,5}-\d{7,8}/.test(n);
80 |
81 | /**
82 | * 判断平台 pc
83 | * @author wm
84 | * @returns {string} 平台类型
85 | */
86 |
87 | const validataOS = () => {
88 | if (navigator.userAgent.indexOf("Window") > 0) {
89 | return "Windows";
90 | } else if (navigator.userAgent.indexOf("Mac OS X") > 0) {
91 | return "Mac";
92 | } else if (navigator.userAgent.indexOf("Linux") > 0) {
93 | return "Linux";
94 | } else {
95 | return "NUll";
96 | }
97 | };
98 | const isWeiXin = () => {
99 | var ua = window.navigator.userAgent.toLowerCase();
100 | if (
101 | ua.match(/MicroMessenger/i) &&
102 | ua.match(/MicroMessenger/i)[0] === "micromessenger"
103 | ) {
104 | return true;
105 | } else {
106 | return false;
107 | }
108 | };
109 | let inBrowser = typeof window !== "undefined";
110 | let UA = inBrowser && window.navigator.userAgent.toLowerCase();
111 |
112 | /**
113 | *是否是android平台
114 | */
115 | const isAndroid = UA && UA.indexOf("android") > 0;
116 |
117 | /**
118 | * 是否是ios平台
119 | */
120 | const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA);
121 |
122 | /**
123 | * 获取滚动条位置
124 | * @return {Number} 滚动条位置
125 | */
126 | const getScrollTop = _ => {
127 | let scrollTop = 0;
128 | if (document.documentElement && document.documentElement.scrollTop) {
129 | scrollTop = document.documentElement.scrollTop;
130 | } else if (document.body) {
131 | scrollTop = document.body.scrollTop;
132 | }
133 | return scrollTop;
134 | };
135 |
136 | /**
137 | * 获取可视范围高度
138 | * @return {Number} 可视范围高度
139 | */
140 | const getClientHeight = _ => {
141 | let clientHeight = 0;
142 | if (document.body.clientHeight && document.documentElement.clientHeight) {
143 | clientHeight = Math.min(
144 | document.body.clientHeight,
145 | document.documentElement.clientHeight
146 | );
147 | } else {
148 | clientHeight = Math.max(
149 | document.body.clientHeight,
150 | document.documentElement.clientHeight
151 | );
152 | }
153 | return clientHeight;
154 | };
155 | /**
156 | * 获取文档完整的高度
157 | * @return {Number} 文档高度
158 | */
159 | const getScrollHeight = _ => {
160 | return Math.max(
161 | document.body.scrollHeight,
162 | document.documentElement.scrollHeight
163 | );
164 | };
165 | /**
166 | * 距离第二天的倒计时
167 | * @return {String} 距离第二天的时间
168 | */
169 | const timeToNextDay = _ => {
170 | // 现在距离 1970-1-1 毫秒数
171 | let d = new Date();
172 | let now = d.getTime();
173 | // 今天凌晨距离 1970-1-1 毫秒数
174 | let today = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
175 | let tomorrow = today + 24 * 60 * 60 * 1000;
176 | let dis = (tomorrow - now) / 1000;
177 | let h = parseInt(dis / (60 * 60));
178 | let m = parseInt((dis / 60) % 60);
179 | let s = parseInt(dis % 60);
180 | return `${h}时${m}分${formatTime(s)}秒`;
181 | };
182 |
183 | const formatTime = s => {
184 | return Number(s) >= 10 ? s : "0" + s;
185 | };
186 |
187 | /**
188 | * 获取某个cookie
189 | * @param {string} name cookie的key
190 | * @return {string} cookie的value
191 | */
192 | const getCookie = name => {
193 | let arr;
194 | let reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
195 | if ((arr = document.cookie.match(reg))) {
196 | return unescape(arr[2]).replace(/\"/g, ""); //替换引号
197 | } else {
198 | return null;
199 | }
200 | };
201 | // const getCookie =(cname) => {
202 | // var name = cname + "=";
203 | // var ca = document.cookie.split(';');
204 | // for (var i = 0; i < ca.length; i++) {
205 | // var c = ca[i].trim();
206 | // if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
207 | // }
208 | // return "";
209 | // }
210 |
211 | /**
212 | * 删除cookie
213 | * @param name cookie的名称
214 | */
215 | const delCookie = name => {
216 | setCookie(name, " ", -1);
217 | };
218 |
219 | /**
220 | * 判断页面登录
221 | * @Author wangmeng
222 | * @DateTime 2019-01-08
223 | */
224 | const getPPU = _ => {
225 | return getCookie("PPU");
226 | };
227 |
228 | /**
229 | * M端登录
230 | * @Author wangmeng
231 | * @DateTime 2019-01-08
232 | * @param url 登录成功后回跳页面
233 | */
234 | const H5Login = url => {
235 | let href = window.location.href;
236 | location.href = `//m.m.58.com/login/?path=${url || href}`;
237 | };
238 |
239 | /**
240 | * 点击复制到剪切板中 使用execCommand API
241 | * https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript/30810322#30810322
242 | * @param {string} text 要复制的内容
243 | * @return {promise} new promise
244 | */
245 |
246 | const fallbackCopyTextToClipboard = text => {
247 | let textArea = document.createElement("textarea");
248 | let root = document.getElementById("app");
249 | textArea.value = text;
250 | // document.body.appendChild(textArea);
251 | document.body.insertBefore(textArea, root);
252 | textArea.focus();
253 | textArea.select();
254 | textArea.setSelectionRange(0, text.length); //不设置的话ios 会有问题
255 | return new Promise((reslove, reject) => {
256 | try {
257 | let success = document.execCommand("copy");
258 | let msg = success ? "success" : "unsuccess";
259 | reslove(msg);
260 | } catch (err) {
261 | reject(err);
262 | }
263 | document.body.removeChild(textArea);
264 | });
265 | };
266 |
267 | /**
268 | * 点击复制到剪切板中 使用 navigator.clipboard.writeText(text)
269 | * @param {string} text 要复制的内容
270 | * @return {promise} new promise
271 | */
272 |
273 | const copyTextToClipboard = text => {
274 | if (!navigator.clipboard) {
275 | return fallbackCopyTextToClipboard(text);
276 | }
277 | return new Promise((reslove, reject) => {
278 | navigator.clipboard.writeText(text).then(
279 | function() {
280 | reslove("success");
281 | },
282 | function(err) {
283 | reject(err);
284 | }
285 | );
286 | });
287 | };
288 |
289 | /**
290 | * 函数防抖
291 | * @param {function} func 需要防抖的函数
292 | * @param {string} wait 时间
293 | * @return {function} 防抖函数
294 | */
295 | const simpleDebounce = (func, wait) => {
296 | let timer;
297 | return _ => {
298 | timer && clearTimeout(timer);
299 | timer = setTimeout(func, wait);
300 | };
301 | };
302 | /**
303 | * 函数防抖
304 | * @param {function} func 需要防抖的函数
305 | * @param {string} wait 时间
306 | * @param {bollean} immediate 是否立即执行
307 | * @return {function} 防抖函数
308 | */
309 | const debounce = (func, wait, immediate) => {
310 | var timeout, result;
311 |
312 | return function() {
313 | var context = this;
314 | var args = arguments;
315 |
316 | if (timeout) clearTimeout(timeout);
317 | if (immediate) {
318 | // 如果已经执行过,不再执行
319 | var callNow = !timeout;
320 | timeout = setTimeout(function() {
321 | timeout = null;
322 | }, wait);
323 | if (callNow) result = func.apply(context, args);
324 | } else {
325 | timeout = setTimeout(function() {
326 | result = func.apply(context, args);
327 | }, wait);
328 | }
329 |
330 | return result;
331 | };
332 | };
333 |
334 | /**
335 | * 函数节流
336 | * @param {function} func 需要节流的函数
337 | * @param {strimg} wait 节流函数
338 | * @return {function} 节流的函数
339 | */
340 | const throttle = (func, wait) => {
341 | if (timer) return;
342 | return () => {
343 | timer = setTimeout(_ => {
344 | func();
345 | timer = null;
346 | }, wait);
347 | };
348 | };
349 |
350 | // const throttle2 = (func, wait) => {
351 | // let last = 0
352 | // return () => {
353 | // let current_time = +new Date()
354 | // if (current_time - last > wait) {
355 | // func.apply(this, arguments)
356 | // last = +new Date()
357 | // }
358 | // }
359 | // }
360 |
361 | /**
362 | * 解析url参数
363 | * @example ?id=12345&a=b
364 | * @return {object} {id:12345, a:b}
365 | * */
366 | const urlParse = () => {
367 | let url = window.location.search;
368 | let obj = {};
369 | let reg = /[?&][^?&]+=[^?&]+/g;
370 | let arr = url.match(reg);
371 | if (arr) {
372 | arr.forEach(item => {
373 | let tempArr = item.substr(1).split("=");
374 | let key = decodeURIComponent(tempArr[0]);
375 | let val = decodeURIComponent(tempArr[1]);
376 | obj[key] = val;
377 | });
378 | }
379 | return obj;
380 | };
381 |
382 | /**
383 | * 根据对象某属性排序
384 | * @Author wangmeng
385 | * @DateTime 2019-01-03
386 | * @param {String} prop 对象属性
387 | * @param {Boolean} boolean 排序规则
388 | */
389 | const sortBy = (prop, boolean = true) => {
390 | let flag = boolean ? 1 : -1;
391 | return function(a, b) {
392 | return a[prop] < b[prop] ? flag * -1 : flag;
393 | };
394 | };
395 |
396 | /**
397 | * 缓存函数计算的结果 仅支持一个参数传递
398 | * @Author wangmeng
399 | * @DateTime 2019-02-11
400 | * @param {Function} fn 要缓存的函数
401 | * @return {Function} 缓存后的函数
402 | * @useage const cachedComputed = cached(funcA); cachedComputed(1)
403 | */
404 |
405 | const cached = fn => {
406 | const cache = Object.create(null);
407 | return function cachedFn(str) {
408 | if (!cache[str]) {
409 | cache[str] = fn(str);
410 | }
411 | return cache[str];
412 | };
413 | };
414 |
415 | export {
416 | scrollToTop,
417 | validateEmail,
418 | validateNumber,
419 | validataPhone,
420 | validataFixedLineTelephone,
421 | validataOS,
422 | isWeiXin,
423 | isAndroid,
424 | isIOS,
425 | getScrollTop,
426 | getClientHeight,
427 | getScrollHeight,
428 | timeToNextDay,
429 | getCookie,
430 | getPPU,
431 | H5Login,
432 | isAPP,
433 | copyTextToClipboard,
434 | simpleDebounce,
435 | debounce, // 节流
436 | throttle, // 防抖
437 | // throttle2, //防抖
438 | urlParse,
439 | sortBy,
440 | animateScroll
441 | };
442 |
--------------------------------------------------------------------------------
/generators/app/templates/dist/skeleton.json:
--------------------------------------------------------------------------------
1 | {
2 | "entry": "skeleton.js",
3 | "files": {
4 | "skeleton.js": "module.exports =\n/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"/dist/\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_vue__ = __webpack_require__(1);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_vue___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_vue__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__components_skeleton_vue__ = __webpack_require__(2);\n\n\n\nconsole.log('Skeleton...')\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (new __WEBPACK_IMPORTED_MODULE_0_vue___default.a({\n components: {\n skeleton: __WEBPACK_IMPORTED_MODULE_1__components_skeleton_vue__[\"a\" /* default */]\n },\n template: ''\n}));\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports) {\n\nmodule.exports = require(\"vue\");\n\n/***/ }),\n/* 2 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__node_modules_vue_loader_lib_template_compiler_index_id_data_v_740ad5dd_hasScoped_false_buble_transforms_node_modules_vue_loader_lib_selector_type_template_index_0_skeleton_vue__ = __webpack_require__(9);\nfunction injectStyle (ssrContext) {\nvar i\n;(i=__webpack_require__(3),i.__inject__&&i.__inject__(ssrContext),i)\n}\nvar normalizeComponent = __webpack_require__(8)\n/* script */\nvar __vue_script__ = null\n/* template */\n\n/* template functional */\nvar __vue_template_functional__ = false\n/* styles */\nvar __vue_styles__ = injectStyle\n/* scopeId */\nvar __vue_scopeId__ = null\n/* moduleIdentifier (server only) */\nvar __vue_module_identifier__ = \"ee7e1cbe\"\nvar Component = normalizeComponent(\n __vue_script__,\n __WEBPACK_IMPORTED_MODULE_0__node_modules_vue_loader_lib_template_compiler_index_id_data_v_740ad5dd_hasScoped_false_buble_transforms_node_modules_vue_loader_lib_selector_type_template_index_0_skeleton_vue__[\"a\" /* default */],\n __vue_template_functional__,\n __vue_styles__,\n __vue_scopeId__,\n __vue_module_identifier__\n)\nComponent.options.__file = \"src/components/skeleton.vue\"\n\n/* harmony default export */ __webpack_exports__[\"a\"] = (Component.exports);\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// style-loader: Adds some css to the DOM by adding a '\n }\n return css\n}\n\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports) {\n\n/**\n * Translates the list format produced by css-loader into something\n * easier to manipulate.\n */\nmodule.exports = function listToStyles (parentId, list) {\n var styles = []\n var newStyles = {}\n for (var i = 0; i < list.length; i++) {\n var item = list[i]\n var id = item[0]\n var css = item[1]\n var media = item[2]\n var sourceMap = item[3]\n var part = {\n id: parentId + ':' + i,\n css: css,\n media: media,\n sourceMap: sourceMap\n }\n if (!newStyles[id]) {\n styles.push(newStyles[id] = { id: id, parts: [part] })\n } else {\n newStyles[id].parts.push(part)\n }\n }\n return styles\n}\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports) {\n\n/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file.\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nmodule.exports = function normalizeComponent (\n rawScriptExports,\n compiledTemplate,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier /* server only */\n) {\n var esModule\n var scriptExports = rawScriptExports = rawScriptExports || {}\n\n // ES6 modules interop\n var type = typeof rawScriptExports.default\n if (type === 'object' || type === 'function') {\n esModule = rawScriptExports\n scriptExports = rawScriptExports.default\n }\n\n // Vue.extend constructor export interop\n var options = typeof scriptExports === 'function'\n ? scriptExports.options\n : scriptExports\n\n // render functions\n if (compiledTemplate) {\n options.render = compiledTemplate.render\n options.staticRenderFns = compiledTemplate.staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = scopeId\n }\n\n var hook\n if (moduleIdentifier) { // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = injectStyles\n }\n\n if (hook) {\n var functional = options.functional\n var existing = functional\n ? options.render\n : options.beforeCreate\n\n if (!functional) {\n // inject component registration as beforeCreate hook\n options.beforeCreate = existing\n ? [].concat(existing, hook)\n : [hook]\n } else {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functioal component in vue file\n options.render = function renderWithStyleInjection (h, context) {\n hook.call(context)\n return existing(h, context)\n }\n }\n }\n\n return {\n esModule: esModule,\n exports: scriptExports,\n options: options\n }\n}\n\n\n/***/ }),\n/* 9 */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"skeleton page\" }, [\n _vm._ssrNode(\n ' ' +\n _vm._ssrList(8, function(i) {\n return ' '\n }) +\n '
' +\n _vm._ssrList(6, function(i) {\n return ''\n })\n )\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\nvar esExports = { render: render, staticRenderFns: staticRenderFns }\n/* harmony default export */ __webpack_exports__[\"a\"] = (esExports);\n\n/***/ })\n/******/ ]);"
5 | },
6 | "maps": {}
7 | }
--------------------------------------------------------------------------------