├── .gitignore
├── config
├── utils.js
└── command.js
├── template
├── entry.ejs
├── routerT
│ ├── childs
│ │ ├── child2.vue
│ │ └── child1.vue
│ ├── entry.ejs
│ ├── html.ejs
│ └── component.ejs
├── html.ejs
└── component.ejs
├── command
├── list.js
├── init.js
├── delete.js
└── add.js
├── package.json
├── README.md
└── bin
└── vue-app
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
--------------------------------------------------------------------------------
/config/utils.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | toHump: str => str.replace(/-(\w)/g,
3 | x => x.slice(1).toUpperCase()),
4 | toLine: str => str.replace(/([A-Z])/g,"-$1").toLowerCase()
5 | }
--------------------------------------------------------------------------------
/config/command.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | init: 'init',
3 | add: 'add',
4 | delete: 'delete',
5 | list: 'list',
6 | i: 'i',
7 | a: 'a',
8 | d: 'd',
9 | l: 'l'
10 | }
--------------------------------------------------------------------------------
/template/entry.ejs:
--------------------------------------------------------------------------------
1 | import <%= pageName %> from "@/components/<%= pageName %>/index"
2 | //使用阿里flexible解决方案
3 | import 'amfe-flexible'
4 |
5 | new Vue({
6 | el: '#app',
7 | components: { <%= pageName %> }
8 | });
9 |
--------------------------------------------------------------------------------
/template/routerT/childs/child2.vue:
--------------------------------------------------------------------------------
1 |
2 | child2
3 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/template/routerT/childs/child1.vue:
--------------------------------------------------------------------------------
1 |
2 | child1
3 |
4 |
5 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/command/list.js:
--------------------------------------------------------------------------------
1 | const exec = require('child_process').exec;
2 | const co = require('co');
3 | const fs = require('fs');
4 | const chalk = require('chalk');
5 |
6 | module.exports = () => {
7 | co(function* () {
8 | fs.readdir('./pages', (err, data) => {
9 | if(err) {
10 | console.log(chalk.red('\n Can not find pages, please make sure that you are in the root of the project'))
11 | process.exit();
12 | }
13 | console.log(data);
14 | process.exit();
15 | })
16 | })
17 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "bin": {
3 | "vue-app": "bin/vue-app"
4 | },
5 | "name": "vue-app-cli",
6 | "version": "1.4.0",
7 | "description": "优化devool",
8 | "main": "index.js",
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "chalk": "^2.3.1",
16 | "co": "^4.6.0",
17 | "co-prompt": "^1.0.0",
18 | "commander": "^2.14.1",
19 | "download-git-repo": "^1.0.2",
20 | "ejs": "^2.5.7",
21 | "ora": "^2.0.0",
22 | "rimraf": "^2.6.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/template/routerT/entry.ejs:
--------------------------------------------------------------------------------
1 | import <%= pageName %> from "@/components/<%= pageName %>/index"
2 | import Child1 from '@/components/<%= pageName %>/childs/child1'
3 | import Child2 from '@/components/<%= pageName %>/childs/child2'
4 | import VueRouter from 'vue-router'
5 | //使用阿里flexible解决方案
6 | import 'amfe-flexible'
7 |
8 | Vue.use(VueRouter)
9 |
10 | const routes = [{
11 | path: '/child1',
12 | component: Child1
13 | }, {
14 | path: '/child2',
15 | component: Child2
16 | }]
17 |
18 | const router = new VueRouter({
19 | routes
20 | })
21 |
22 | new Vue({
23 | el: '#app',
24 | router,
25 | components: { <%= pageName %> }
26 | });
27 |
--------------------------------------------------------------------------------
/template/html.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= pageName %>
7 |
8 |
9 |
10 |
11 |
12 |
13 | <<%= labelName %>><%= labelName %>>
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/template/component.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
This is the {{pageName}} page.
6 |
7 |
8 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/template/routerT/html.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= pageName %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | <<%= labelName %>><%= labelName %>>
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/template/routerT/component.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
This is the {{pageName}} page.
6 |
Go to Child1
7 |
Go to Child2
8 |
9 |
10 |
11 |
12 |
13 |
23 |
24 |
--------------------------------------------------------------------------------
/command/init.js:
--------------------------------------------------------------------------------
1 | const co = require('co');
2 | const chalk = require('chalk');
3 | const download = require('download-git-repo');
4 | const ora = require('ora');
5 | const exists = require('fs').existsSync;
6 | const rm = require('rimraf').sync;
7 |
8 | module.exports = (projectName) => {
9 | co(function*() {
10 | console.log(chalk.white('\n Start generating...'));
11 | const spinner = ora('Start downloading templates...').start();
12 | if (exists(projectName)) rm(projectName);
13 | download('1335382915/vue-app-template', projectName, (err) => {
14 | if(err) {
15 | console.log(chalk.red(err));
16 | process.exit();
17 | }
18 | spinner.stop();
19 | console.log(chalk.green('\n Download succeed! Enter your project and use `npm install`'));
20 | process.exit();
21 | })
22 | })
23 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | ### 一个能够让你快速构建基于`vue`的`app`多页应用脚手架,可独立开发`h5 app`或集成到`hbuilder`开发原生应用。
6 |
7 | ### [文档地址](https://mescalchuan.github.io/vue-app-cli)
8 |
9 | #### vue-cli
10 | 之所以不使用官方的`vue-cli`构建应用是因为:
11 | * `vue-cli`需要自己实现多页面构建。
12 | * 在开发环境(`npm start`)下会创建服务器,一切构建结果都存放在内存中,本地无法访问,导致`app`变为空白页。
13 | * 只有在生产环境(`npm run build`)下才会构建到本地,却失去了对模块的实时监控。
14 | * `webpack`拆分太细,功能太全,很多功能在`app`端都不会用到。
15 |
16 | 以上不足均可以自行修改`vue-cli`实现构建最优化,出于时间成本的考虑,最终决定在已有的`angular-m-cli`的基础上完成适合`app`开发的脚手架构建。
17 |
18 | #### vue-app-cli
19 | 可以快速构建基于vue的app多页应用,对`h5页面app`和`dcloud原生app`都十分友好。
20 |
21 | 它实现了以下功能:
22 | * 快速生成`app`模板
23 | * 快速创建新页面
24 | * 支持`es6`
25 | * 支持`.vue`文件
26 | * 基于`sass`编写样式文件
27 | * 模块导入样式文件
28 | * 错误映射
29 |
30 | ### 参考
31 | [vue-cli](https://github.com/vuejs/vue-cli)、[教你从零开始搭建一款前端脚手架工具](https://segmentfault.com/a/1190000006190814)
32 |
33 |
--------------------------------------------------------------------------------
/bin/vue-app:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict'
3 | process.env.NODE_PATH = __dirname + '/../node_modules/';
4 |
5 | const program = require('commander');
6 | const commandConfig = require('../config/command');
7 | const add = require('../command/add');
8 | const list = require('../command/list');
9 | const _delete = require('../command/delete');
10 | const init = require('../command/init');
11 |
12 | program.version('1.4.0', '-v', '--version');
13 |
14 | program.usage('');
15 |
16 | program
17 | .command('init ')
18 | .description('Create a new project')
19 | .alias('i')
20 | .action(projectName => {
21 | init(projectName)
22 | });
23 |
24 | program
25 | .command('add ')
26 | .option('-r, --vuerouter', 'use vue-router page')
27 | .description('Add a new page, use -vr to add a vue-router-page')
28 | .alias('a')
29 | .action((pageName, cmd) => {
30 | add(pageName, cmd.vuerouter ? 'vr' : '')
31 | });
32 |
33 | program
34 | .command('list')
35 | .description('List all the pages')
36 | .alias('l')
37 | .action(() => {
38 | list()
39 | });
40 |
41 | program
42 | .command('delete ')
43 | .description('Delete a page')
44 | .alias('d')
45 | .action(pageName => {
46 | _delete(pageName)
47 | });
48 |
49 | program.parse(process.argv)
50 |
51 | if(!program.args.length){
52 | program.help()
53 | }
54 |
--------------------------------------------------------------------------------
/command/delete.js:
--------------------------------------------------------------------------------
1 | const co = require('co');
2 | const fs = require('fs');
3 | const chalk = require('chalk');
4 | const ora = require('ora');
5 | const rm = require('rimraf').sync;
6 | const prompt = require('co-prompt');
7 |
8 | module.exports = (pageName) => {
9 | co(function* () {
10 | const containerName = pageName;
11 |
12 | console.log(chalk.yellow(`\n Your './entry/${containerName}.js, './pages/${containerName}.html', './components/${containerName}' will be removed.`));
13 | const answer = yield prompt('\n are you sure? Input y or n \n');
14 |
15 | if(answer == 'n' || !answer) process.exit();
16 |
17 | const destinationEntry = `./entry/${containerName}.js`;
18 | const destinationPage = `./pages/${containerName}.html`;
19 | const destinationComponent = `./components/${containerName}`;
20 |
21 | try {
22 | fs.readFileSync(destinationEntry);
23 | fs.readFileSync(destinationPage);
24 | fs.readdirSync(destinationComponent);
25 | }
26 | catch(err) {
27 | console.log(chalk.red(`\n Can not find ${containerName}.`));
28 | process.exit();
29 | }
30 |
31 | const spinner = ora(`Deleting ${containerName} pages...`).start();
32 | try {
33 | rm(destinationEntry);
34 | rm(destinationPage);
35 | rm(destinationComponent);
36 | }
37 | catch(err) {
38 | spinner.stop();
39 | console.log(chalk.red(`\n Can not delete ${containerName}`));
40 | process.exit();
41 | }
42 | spinner.stop();
43 | console.log(chalk.green('\n Delete succeed!'));
44 | process.exit();
45 | })
46 | }
--------------------------------------------------------------------------------
/command/add.js:
--------------------------------------------------------------------------------
1 | const co = require('co')
2 | const ejs = require('ejs');
3 | const fs = require('fs');
4 | const chalk = require('chalk')
5 | const path = require('path');
6 | const ora = require('ora');
7 | const utils = require('../config/utils');
8 |
9 | module.exports = (pageName, vr) => {
10 | co(function*() {
11 | //读取模板文件
12 | const vrPath = vr ? 'routerT/' : ''
13 | const entryEJS = fs.readFileSync(path.resolve(__dirname, `../template/${vrPath}entry.ejs`), 'utf-8');
14 | const htmlEJS = fs.readFileSync(path.resolve(__dirname, `../template/${vrPath}html.ejs`), 'utf-8');
15 | const componentEJS = fs.readFileSync(path.resolve(__dirname, `../template/${vrPath}component.ejs`), 'utf-8');
16 |
17 | //参数获取新建container名字并转换成驼峰
18 | const containerName = utils.toHump(pageName);
19 | const labelName = utils.toLine(containerName);
20 | //文件路径
21 | const destinationEntryJS = `./entry/${containerName}.js`;
22 | const destinationPageHTML = `./pages/${containerName}.html`;
23 | const destinationComponent = `./components/${containerName}`;
24 | const destinationComponentVue = `./components/${containerName}/index.vue`;
25 |
26 | //渲染模板文件
27 | const entryResult = ejs.render(entryEJS, {pageName: containerName});
28 | const htmlResult = ejs.render(htmlEJS, {pageName: containerName, labelName});
29 | const componentResult = ejs.render(componentEJS, {pageName: containerName});
30 |
31 | const entryExist = fs.existsSync(destinationEntryJS);
32 | const pageExist = fs.existsSync(destinationPageHTML);
33 | const componentPathExist = fs.existsSync(destinationComponent);
34 | if(entryExist) {
35 | console.log(chalk.red(`\n The project has the same container, see your entry/${containerName}.js`));
36 | process.exit();
37 | }
38 | if(pageExist) {
39 | console.log(chalk.red(`\n The project has the same container, see your pages/${containerName}.html`));
40 | process.exit();
41 | }
42 | if(componentPathExist) {
43 | console.log(chalk.red(`\n The project has the same container, see your components/${containerName} folder.`));
44 | process.exit();
45 | }
46 |
47 | //复制文件
48 | const spinner = ora(`Creating ${containerName} pages...`).start();
49 | try {
50 | fs.mkdirSync(destinationComponent);
51 | fs.writeFileSync(destinationEntryJS, entryResult);
52 | fs.writeFileSync(destinationPageHTML, htmlResult);
53 | fs.writeFileSync(destinationComponentVue, componentResult);
54 | if(vr) {
55 | fs.mkdirSync(`./components/${containerName}/childs`);
56 |
57 | const destinationRouterChild1 = `./components/${containerName}/childs/child1.vue`;
58 | const destinationRouterChild2 = `./components/${containerName}/childs/child2.vue`;
59 |
60 | const child1Vue = fs.readFileSync(path.resolve(__dirname, '../template/routerT/childs/child1.vue'), 'utf-8');
61 | const child2Vue = fs.readFileSync(path.resolve(__dirname, '../template/routerT/childs/child2.vue'), 'utf-8');
62 |
63 | fs.writeFileSync(destinationRouterChild1, child1Vue);
64 | fs.writeFileSync(destinationRouterChild2, child2Vue);
65 | }
66 | }
67 | catch(err) {
68 | spinner.stop();
69 | console.log(chalk.red('\n Can not create new page.'));
70 | console.log(err);
71 | process.exit();
72 | }
73 | spinner.stop();
74 | console.log(chalk.green('\n Create succeed!'));
75 | process.exit();
76 | })
77 | }
--------------------------------------------------------------------------------