11 |
12 |
Athena SiteMap
13 | <%= htmlWebpackPlugin.options.title %>项目
14 |
15 | <% const htmlPages = htmlWebpackPlugin.options.data.htmlPages %>
16 | <% for (const mod in htmlPages) { %>
17 |
18 |
<%= mod %>
19 |
25 |
26 | <% } %>
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/create/app.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const path = require('path')
3 | const chalk = require('chalk')
4 | const inquirer = require('inquirer')
5 | const uuid = require('uuid')
6 |
7 | const CreateBase = require('./base')
8 |
9 | const {
10 | shouldUseYarn,
11 | shouldUseCnpm
12 | } = require('../util')
13 |
14 | class App extends CreateBase {
15 | constructor (options) {
16 | super()
17 | this.rootPath = this._rootPath
18 | this.conf = Object.assign({
19 | appName: null,
20 | description: '',
21 | framework: null,
22 | template: null,
23 | platform: null,
24 | sass: false
25 | }, options)
26 | }
27 |
28 | init () {
29 | console.log(chalk.green(`Allo ${chalk.green.bold(this.username)}! Prepare to create a new app!`))
30 | console.log('Need help? Go and open issue: https://github.com/o2team/athena2/issues/new')
31 | console.log()
32 | }
33 |
34 | create () {
35 | this.ask()
36 | .then(answers => {
37 | this.askOther(answers.template || this.conf.template)
38 | .then(otherAnswers => {
39 | const date = new Date()
40 | this.conf = Object.assign(this.conf, answers, otherAnswers)
41 | this.conf.appId = uuid.v1()
42 | this.conf.date = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`
43 | this.write()
44 | })
45 | })
46 | }
47 |
48 | ask () {
49 | const prompts = []
50 | const conf = this.conf
51 | if (typeof conf.appName !== 'string') {
52 | prompts.push({
53 | type: 'input',
54 | name: 'appName',
55 | message: 'Please give me an app name!',
56 | validate (input) {
57 | if (!input) {
58 | return 'App name can not be empty!'
59 | }
60 | if (fs.existsSync(input)) {
61 | return 'Already existing the app name, choose another name please!'
62 | }
63 | return true
64 | }
65 | })
66 | } else if (fs.existsSync(conf.appName)) {
67 | prompts.push({
68 | type: 'input',
69 | name: 'appName',
70 | message: 'Already existing the app, choose another name please!',
71 | validate (input) {
72 | if (!input) {
73 | return 'App name can not be empty!'
74 | }
75 | if (fs.existsSync(input)) {
76 | return 'The app name is still repeated!'
77 | }
78 | return true
79 | }
80 | })
81 | }
82 |
83 | if (typeof conf.description !== 'string') {
84 | prompts.push({
85 | type: 'input',
86 | name: 'description',
87 | message: 'Please tell me your app\'s description!'
88 | })
89 | }
90 |
91 | const platformChoices = [{
92 | name: 'PC',
93 | value: 'pc'
94 | }, {
95 | name: 'Mobile',
96 | value: 'mobile'
97 | }]
98 |
99 | if (typeof conf.platform !== 'string') {
100 | prompts.push({
101 | type: 'list',
102 | name: 'platform',
103 | message: 'Please choose your app platform',
104 | choices: platformChoices
105 | })
106 | } else {
107 | let isPlatformExist = false
108 | platformChoices.forEach(item => {
109 | if (item.value === conf.template) {
110 | isPlatformExist = true
111 | }
112 | })
113 | if (!isPlatformExist) {
114 | console.log(chalk.red('The platform you choose is not exist!'))
115 | console.log(chalk.red('Currently there are the following platforms to choose from:'))
116 | console.log()
117 | platformChoices.forEach(item => {
118 | console.log(chalk.green(`- ${item.name}`))
119 | })
120 | process.exit(1)
121 | }
122 | }
123 |
124 | const templateChoices = [{
125 | name: 'Complete(Complex project like multi-page application should use this template)',
126 | value: 'complete'
127 | }, {
128 | name: 'Simple(Simple template like single-page application for simple project)',
129 | value: 'simple'
130 | }, {
131 | name: 'H5(Like Interactive game OR Operational activities)',
132 | value: 'h5'
133 | }]
134 |
135 | if (typeof conf.template !== 'string' && !conf.h5) {
136 | prompts.push({
137 | type: 'list',
138 | name: 'template',
139 | message: 'Please choose your favorite template',
140 | choices: templateChoices
141 | })
142 | } else if (conf.h5) {
143 | conf.template = 'h5'
144 | } else {
145 | let isTemplateExist = false
146 | templateChoices.forEach(item => {
147 | if (item.value === conf.template) {
148 | isTemplateExist = true
149 | }
150 | })
151 | if (!isTemplateExist) {
152 | console.log(chalk.red('The template you choose is not exist!'))
153 | console.log(chalk.red('Currently there are the following templates to choose from:'))
154 | console.log()
155 | templateChoices.forEach(item => {
156 | console.log(chalk.green(`- ${item.name}`))
157 | })
158 | process.exit(1)
159 | }
160 | }
161 |
162 | return inquirer.prompt(prompts)
163 | }
164 |
165 | askOther (template) {
166 | const newPrompts = []
167 | const conf = this.conf
168 | const frameworkChoices = [{
169 | name: 'Nerv',
170 | value: 'nerv'
171 | }, {
172 | name: 'React',
173 | value: 'react'
174 | }, {
175 | name: 'Vue',
176 | value: 'vue'
177 | }]
178 | if (template === 'h5') {
179 | conf.framework = 'base'
180 | if (typeof conf.h5 !== 'string') {
181 | newPrompts.push({
182 | type: 'input',
183 | name: 'h5',
184 | message: 'Please tell me which h5 template you prepare to use, default to base!',
185 | validate (input) {
186 | if (!input) {
187 | conf.h5 = 'base'
188 | }
189 | return true
190 | }
191 | })
192 | }
193 | } else {
194 | if (typeof conf.framework !== 'string') {
195 | newPrompts.push({
196 | type: 'list',
197 | name: 'framework',
198 | message: 'Please choose your favorite framework',
199 | choices: frameworkChoices
200 | })
201 | } else {
202 | let isFrameworkExist = false
203 | frameworkChoices.forEach(item => {
204 | if (item.value === conf.framework) {
205 | isFrameworkExist = true
206 | }
207 | })
208 | if (!isFrameworkExist) {
209 | console.log(chalk.red('The framework you choose is not exist!'))
210 | console.log(chalk.red('Currently there are the following frameworks to choose from:'))
211 | console.log()
212 | frameworkChoices.forEach(item => {
213 | console.log(chalk.green(`- ${item.name}`))
214 | })
215 | process.exit(1)
216 | }
217 | }
218 |
219 | if (!conf.sass) {
220 | newPrompts.push({
221 | type: 'confirm',
222 | name: 'sass',
223 | message: 'Do you wanna use sass?'
224 | })
225 | }
226 | }
227 |
228 | return inquirer.prompt(newPrompts)
229 | }
230 |
231 | write () {
232 | const { template } = this.conf
233 |
234 | const templateCreate = require(path.join(this.templatePath(), template, 'index.js'))
235 | templateCreate.app(this, this.conf, {
236 | shouldUseYarn,
237 | shouldUseCnpm
238 | })
239 | }
240 | }
241 |
242 | module.exports = App
243 |
--------------------------------------------------------------------------------
/src/create/base.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash')
2 | const path = require('path')
3 | const fs = require('fs-extra')
4 | const memFs = require('mem-fs')
5 | const editor = require('mem-fs-editor')
6 |
7 | const {
8 | getConfig,
9 | getSystemUsername,
10 | getRootPath,
11 | setConfig
12 | } = require('../util')
13 |
14 | class CreateBase {
15 | constructor () {
16 | const store = memFs.create()
17 | this.fs = editor.create(store)
18 | this.username = getConfig().username
19 | this.appConfPath = this.destinationPath('app.conf.js')
20 | this._ = _
21 |
22 | if (!this.username) {
23 | this.username = getSystemUsername()
24 | setConfig({ username: this.username })
25 | }
26 | this.sourceRoot(path.join(getRootPath()))
27 | this.init()
28 | }
29 |
30 | init () {}
31 |
32 | sourceRoot (rootPath) {
33 | if (typeof rootPath === 'string') {
34 | this._rootPath = path.resolve(rootPath)
35 | }
36 | if (!fs.existsSync(this._rootPath)) {
37 | fs.ensureDirSync(this._rootPath)
38 | }
39 | return this._rootPath
40 | }
41 |
42 | templatePath () {
43 | let filepath = path.join.apply(path, arguments)
44 | if (!path.isAbsolute(filepath)) {
45 | filepath = path.join(this._rootPath, 'templates', filepath)
46 | }
47 | return filepath
48 | }
49 |
50 | destinationRoot (rootPath) {
51 | if (typeof rootPath === 'string') {
52 | this._destinationRoot = path.resolve(rootPath)
53 | if (!fs.existsSync(rootPath)) {
54 | fs.ensureDirSync(rootPath)
55 | }
56 | process.chdir(rootPath)
57 | }
58 | return this._destinationRoot || process.cwd()
59 | }
60 |
61 | destinationPath () {
62 | let filepath = path.join.apply(path, arguments)
63 | if (!path.isAbsolute(filepath)) {
64 | filepath = path.join(this.destinationRoot(), filepath)
65 | }
66 | return filepath
67 | }
68 |
69 | template (template, type, source, dest, data, options) {
70 | if (typeof dest !== 'string') {
71 | options = data
72 | data = dest
73 | dest = source
74 | }
75 | this.fs.copyTpl(
76 | this.templatePath(template, type, source),
77 | this.destinationPath(dest),
78 | _.assign(this, data),
79 | options
80 | )
81 | return this
82 | }
83 |
84 | copy (template, type, source, dest) {
85 | dest = dest || source
86 | this.template(template, type, source, dest)
87 | return this
88 | }
89 |
90 | writeGitKeepFile (dirname) {
91 | dirname = path.resolve(dirname)
92 | fs.writeFileSync(path.join(dirname, '.gitkeep'), 'Place hold file', 'utf8')
93 | }
94 |
95 | write () {}
96 | }
97 |
98 | module.exports = CreateBase
99 |
--------------------------------------------------------------------------------
/src/create/component.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const path = require('path')
3 | const chalk = require('chalk')
4 | const inquirer = require('inquirer')
5 |
6 | const CreateBase = require('./base')
7 |
8 | class Component extends CreateBase {
9 | constructor (options) {
10 | super()
11 | this.conf = Object.assign({
12 | appName: null,
13 | template: null,
14 | framework: null,
15 | componentName: null,
16 | description: ''
17 | }, options)
18 | }
19 |
20 | init () {
21 | console.log(chalk.green(`Allo ${chalk.green.bold(this.username)}! Prepare to create a new component!`))
22 | console.log('Need help? Go and open issue: https://github.com/o2team/athena2/issues/new')
23 | console.log()
24 | }
25 |
26 | create () {
27 | this.ask()
28 | .then(answers => {
29 | const date = new Date()
30 | this.conf = Object.assign(this.conf, answers)
31 | this.conf.date = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`
32 | this.write()
33 | })
34 | }
35 |
36 | ask () {
37 | const prompts = []
38 | const conf = this.conf
39 | if (typeof conf.componentName !== 'string') {
40 | prompts.push({
41 | type: 'input',
42 | name: 'componentName',
43 | message: 'Please give me a component name!',
44 | validate (input) {
45 | if (!input) {
46 | return 'component\'s name can not be empty!'
47 | }
48 | if (fs.existsSync(`component/${input}`) || fs.existsSync(`src/component/${input}`) || fs.existsSync(`src/js/${input}.js`)) {
49 | return 'The component already exist, please give me another name!'
50 | }
51 | return true
52 | }
53 | })
54 | } else if (fs.existsSync(`component/${conf.componentName}`) ||
55 | fs.existsSync(`src/component/${conf.componentName}`) ||
56 | fs.existsSync(`src/js/${conf.componentName}.js`)) {
57 | prompts.push({
58 | type: 'input',
59 | name: 'componentName',
60 | message: 'The component already exist, please give me another name!',
61 | validate (input) {
62 | if (!input) {
63 | return 'component\'s name can not be empty!'
64 | }
65 | if (fs.existsSync(`component/${input}`) ||
66 | fs.existsSync(`src/component/${input}`) ||
67 | fs.existsSync(`src/js/${input}.js`)) {
68 | return 'You type the component name repeatedly!'
69 | }
70 | return true
71 | }
72 | })
73 | }
74 |
75 | if (typeof conf.description !== 'string') {
76 | prompts.push({
77 | type: 'input',
78 | name: 'description',
79 | message: 'Please tell me this component\'s description!'
80 | })
81 | }
82 |
83 | return inquirer.prompt(prompts)
84 | }
85 |
86 | write () {
87 | const { template } = this.conf
88 |
89 | const templateCreate = require(path.join(this.templatePath(), template, 'index.js'))
90 | templateCreate.component(this, this.conf)
91 | }
92 | }
93 |
94 | module.exports = Component
95 |
--------------------------------------------------------------------------------
/src/create/module.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const path = require('path')
3 | const chalk = require('chalk')
4 | const inquirer = require('inquirer')
5 |
6 | const CreateBase = require('./base')
7 |
8 | class Module extends CreateBase {
9 | constructor (options) {
10 | super()
11 | this.conf = Object.assign({
12 | appName: null,
13 | template: null,
14 | moduleName: null,
15 | description: ''
16 | }, options)
17 | }
18 |
19 | init () {
20 | console.log(chalk.green(`Allo ${chalk.green.bold(this.username)}! Prepare to create a new module!`))
21 | console.log('Need help? Go and open issue: https://github.com/o2team/athena2/issues/new')
22 | console.log()
23 | }
24 |
25 | create () {
26 | this.ask()
27 | .then(answers => {
28 | const date = new Date()
29 | this.conf = Object.assign(this.conf, answers)
30 | this.conf.date = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`
31 | this.write()
32 | })
33 | }
34 |
35 | ask () {
36 | const prompts = []
37 | const conf = this.conf
38 | if (typeof conf.moduleName !== 'string') {
39 | prompts.push({
40 | type: 'input',
41 | name: 'moduleName',
42 | message: 'Please give me a module name!',
43 | validate (input) {
44 | if (!input) {
45 | return 'Module name can not be empty!'
46 | }
47 | if (fs.existsSync(`src/${input}`)) {
48 | return 'The module already exist, please give me another name!'
49 | }
50 | return true
51 | }
52 | })
53 | } else if (fs.existsSync(`src/${conf.moduleName}`)) {
54 | prompts.push({
55 | type: 'input',
56 | name: 'moduleName',
57 | message: 'The module already exist, please give me another name!',
58 | validate (input) {
59 | if (!input) {
60 | return 'Module name can not be empty!'
61 | }
62 | if (fs.existsSync(`src/${input}`)) {
63 | return 'You type the module name repeatedly!'
64 | }
65 | return true
66 | }
67 | })
68 | }
69 |
70 | if (typeof conf.description !== 'string') {
71 | prompts.push({
72 | type: 'input',
73 | name: 'description',
74 | message: 'Please tell me this module\'s description!'
75 | })
76 | }
77 |
78 | return inquirer.prompt(prompts)
79 | }
80 |
81 | write () {
82 | const { template } = this.conf
83 | const templateCreate = require(path.join(this.templatePath(), template, 'index.js'))
84 | templateCreate.module(this, this.conf)
85 | }
86 | }
87 |
88 | module.exports = Module
89 |
--------------------------------------------------------------------------------
/src/create/page.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const path = require('path')
3 | const chalk = require('chalk')
4 | const inquirer = require('inquirer')
5 |
6 | const CreateBase = require('./base')
7 |
8 | class Page extends CreateBase {
9 | constructor (options) {
10 | super()
11 | this.conf = Object.assign({
12 | appName: null,
13 | template: null,
14 | framework: null,
15 | pageName: null,
16 | description: ''
17 | }, options)
18 | }
19 |
20 | init () {
21 | console.log(chalk.green(`Allo ${chalk.green.bold(this.username)}! Prepare to create a new page!`))
22 | console.log('Need help? Go and open issue: https://github.com/o2team/athena2/issues/new')
23 | console.log()
24 | }
25 |
26 | create () {
27 | this.ask()
28 | .then(answers => {
29 | const date = new Date()
30 | this.conf = Object.assign(this.conf, answers)
31 | this.conf.date = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`
32 | this.write()
33 | })
34 | }
35 |
36 | ask () {
37 | const prompts = []
38 | const conf = this.conf
39 | if (typeof conf.pageName !== 'string') {
40 | prompts.push({
41 | type: 'input',
42 | name: 'pageName',
43 | message: 'Please give me a page name!',
44 | validate (input) {
45 | if (!input) {
46 | return 'Page\'s name can not be empty!'
47 | }
48 | if (fs.existsSync(`page/${input}`) || fs.existsSync(`src/view/${input}`)) {
49 | return 'The page already exist, please give me another name!'
50 | }
51 | return true
52 | }
53 | })
54 | } else if (fs.existsSync(`page/${conf.pageName}`) || fs.existsSync(`src/view/${conf.pageName}`)) {
55 | prompts.push({
56 | type: 'input',
57 | name: 'pageName',
58 | message: 'The page already exist, please give me another name!',
59 | validate (input) {
60 | if (!input) {
61 | return 'Page\'s name can not be empty!'
62 | }
63 | if (fs.existsSync(`page/${input}`) || fs.existsSync(`src/view/${input}`)) {
64 | return 'You type the page name repeatedly!'
65 | }
66 | return true
67 | }
68 | })
69 | }
70 |
71 | if (typeof conf.description !== 'string') {
72 | prompts.push({
73 | type: 'input',
74 | name: 'description',
75 | message: 'Please tell me this page\'s description!'
76 | })
77 | }
78 |
79 | return inquirer.prompt(prompts)
80 | }
81 |
82 | write () {
83 | const { template } = this.conf
84 |
85 | const templateCreate = require(path.join(this.templatePath(), template, 'index.js'))
86 | templateCreate.page(this, this.conf)
87 | }
88 | }
89 |
90 | module.exports = Page
91 |
--------------------------------------------------------------------------------
/src/publish/index.js:
--------------------------------------------------------------------------------
1 | // const fs = require('fs')
2 | // const path = require('path')
3 | const FTPS = require('ftps')
4 | /*
5 | 获取配置项
6 | */
7 | const {
8 | getConf,
9 | getAppBuildConfig
10 | } = require('../build')
11 |
12 | module.exports = function publish () {
13 | const conf = getConf()
14 | const buildConfig = getAppBuildConfig(conf.appPath)
15 | const { publish } = buildConfig
16 | createConnect(publish)
17 | }
18 |
19 | function createConnect (opts) {
20 | const ftps = new FTPS(opts)
21 | ftps.exec(function (err, res) {
22 | console.log(err)
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/src/util/format_webpack_message.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk')
2 |
3 | const syntaxErrorLabel = 'Syntax error:'
4 |
5 | function isLikelyASyntaxError (message) {
6 | return message.indexOf(syntaxErrorLabel) >= 0
7 | }
8 |
9 | function formatMessage (message) {
10 | let lines = message.split('\n')
11 | if (lines.length > 2 && lines[1] === '') {
12 | lines.splice(1, 1)
13 | }
14 | if (lines[0].lastIndexOf('!') >= 0) {
15 | lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1)
16 | }
17 | lines = lines.filter(line => line.indexOf(' @ ') !== 0)
18 | if (!lines[0] || !lines[1]) {
19 | return lines.join('\n')
20 | }
21 | if (lines[1].indexOf('Module not found: ') === 0) {
22 | lines = [
23 | lines[0],
24 | lines[1]
25 | .replace("Cannot resolve 'file' or 'directory' ", '')
26 | .replace('Cannot resolve module ', '')
27 | .replace('Error: ', '')
28 | .replace('[CaseSensitivePathsPlugin] ', '')
29 | ]
30 | } else if (lines[1].indexOf('Module build failed: ') === 0) {
31 | lines[1] = lines[1].replace(
32 | 'Module build failed: SyntaxError:',
33 | syntaxErrorLabel
34 | )
35 | }
36 |
37 | const exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/
38 | if (lines[1].match(exportError)) {
39 | lines[1] = lines[1].replace(
40 | exportError,
41 | "$1 '$4' does not contain an export named '$3'."
42 | )
43 | }
44 | lines[0] = chalk.inverse(lines[0])
45 | message = lines.join('\n')
46 |
47 | message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, '')
48 | return message.trim()
49 | }
50 |
51 | module.exports = function formatWebpackMessage (message) {
52 | const errors = message.errors.map(item => formatMessage(item))
53 | const warnings = message.warnings.map(item => formatMessage(item))
54 |
55 | const result = {
56 | errors,
57 | warnings
58 | }
59 | if (result.errors.some(isLikelyASyntaxError)) {
60 | result.errors = result.errors.filter(isLikelyASyntaxError)
61 | }
62 | return result
63 | }
64 |
--------------------------------------------------------------------------------
/src/util/index.js:
--------------------------------------------------------------------------------
1 | const os = require('os')
2 | const path = require('path')
3 | const fs = require('fs-extra')
4 | const execSync = require('child_process').execSync
5 |
6 | /**
7 | * get user dir
8 | */
9 | exports.homedir = (function () {
10 | let homedir = null
11 | const env = process.env
12 | const home = env.HOME
13 | const user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME
14 | if (process.platform === 'win32') {
15 | homedir = env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null
16 | } else if (process.platform === 'darwin') {
17 | homedir = home || (user ? `/Users/${user}` : null)
18 | } else if (process.platform === 'linux') {
19 | homedir = home || (process.getuid() === 0 ? '/root' : (user ? `/home/${user}` : null))
20 | }
21 | return typeof os.homedir === 'function' ? os.homedir : function () {
22 | return homedir
23 | }
24 | })()
25 |
26 | exports.getRootPath = function () {
27 | return path.resolve(__dirname, '../../')
28 | }
29 |
30 | /**
31 | * get athena cache base root
32 | */
33 | exports.getAthenaPath = function () {
34 | const athenaPath = path.join(exports.homedir(), '.athena2')
35 | if (!fs.existsSync(athenaPath)) {
36 | fs.mkdirSync(athenaPath)
37 | }
38 | return athenaPath
39 | }
40 |
41 | /**
42 | * set athena config
43 | */
44 | exports.setConfig = function (config) {
45 | const athenaPath = exports.getAthenaPath()
46 | if (typeof config === 'object') {
47 | const oldConfig = exports.getConfig()
48 | config = Object.assign({}, oldConfig, config)
49 | fs.writeFileSync(path.join(athenaPath, 'config.json'), JSON.stringify(config, null, 2))
50 | }
51 | }
52 |
53 | /**
54 | * get athena config
55 | */
56 | exports.getConfig = function () {
57 | const configPath = path.join(exports.getAthenaPath(), 'config.json')
58 | if (fs.existsSync(configPath)) {
59 | return require(configPath)
60 | }
61 | return {}
62 | }
63 |
64 | exports.getSystemUsername = function () {
65 | const userHome = exports.homedir()
66 | const systemUsername = process.env.USER || path.basename(userHome)
67 | return systemUsername
68 | }
69 |
70 | exports.getAthenaVersion = function () {
71 | return require(path.join(exports.getRootPath(), 'package.json')).version
72 | }
73 |
74 | exports.printAthenaVersion = function () {
75 | const athenaVersion = exports.getAthenaVersion()
76 | console.log(`👩 Athena v${athenaVersion}`)
77 | console.log()
78 | }
79 |
80 | exports.shouldUseYarn = function () {
81 | try {
82 | execSync('yarn --version', { stdio: 'ignore' })
83 | return true
84 | } catch (e) {
85 | return false
86 | }
87 | }
88 |
89 | exports.shouldUseCnpm = function () {
90 | try {
91 | execSync('cnpm --version', { stdio: 'ignore' })
92 | return true
93 | } catch (e) {
94 | return false
95 | }
96 | }
97 |
98 | function _normalizeFamily (family) {
99 | return family ? family.toLowerCase() : 'ipv4'
100 | }
101 |
102 | exports.getLocalIp = function (name, family) {
103 | const interfaces = os.networkInterfaces()
104 | //
105 | // Default to `ipv4`
106 | //
107 | family = _normalizeFamily(family)
108 |
109 | //
110 | // If a specific network interface has been named,
111 | // return the address.
112 | //
113 | if (name && name !== 'private' && name !== 'public') {
114 | const res = interfaces[name].filter(details => {
115 | const itemFamily = details.family.toLowerCase()
116 | return itemFamily === family
117 | })
118 | if (res.length === 0) {
119 | return undefined
120 | }
121 | return res[0].address
122 | }
123 |
124 | const all = Object.keys(interfaces).map(nic => {
125 | //
126 | // Note: name will only be `public` or `private`
127 | // when this is called.
128 | //
129 | const addresses = interfaces[nic].filter(details => {
130 | details.family = details.family.toLowerCase()
131 | if (details.family !== family || exports.isLoopback(details.address)) {
132 | return false
133 | } else if (!name) {
134 | return true
135 | }
136 |
137 | return name === 'public' ? !exports.isPrivate(details.address)
138 | : exports.isPrivate(details.address)
139 | })
140 | return addresses.length ? addresses[0].address : undefined
141 | }).filter(Boolean)
142 |
143 | return !all.length ? exports.loopback(family) : all[0]
144 | }
145 |
146 | exports.loopback = function loopback (family) {
147 | //
148 | // Default to `ipv4`
149 | //
150 | family = _normalizeFamily(family)
151 |
152 | if (family !== 'ipv4' && family !== 'ipv6') {
153 | throw new Error('family must be ipv4 or ipv6')
154 | }
155 |
156 | return family === 'ipv4' ? '127.0.0.1' : 'fe80::1'
157 | }
158 |
159 | exports.isLoopback = function isLoopback (addr) {
160 | return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/
161 | .test(addr) ||
162 | /^fe80::1$/.test(addr) ||
163 | /^::1$/.test(addr) ||
164 | /^::$/.test(addr)
165 | }
166 |
167 | exports.isPrivate = function isPrivate (addr) {
168 | return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/
169 | .test(addr) ||
170 | /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/.test(addr) ||
171 | /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/
172 | .test(addr) ||
173 | /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.test(addr) ||
174 | /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/.test(addr) ||
175 | /^fc00:/i.test(addr) ||
176 | /^fe80:/i.test(addr) ||
177 | /^::1$/.test(addr) ||
178 | /^::$/.test(addr)
179 | }
180 |
181 | exports.isPublic = function isPublic (addr) {
182 | return !exports.isPrivate(addr)
183 | }
184 |
185 | exports.zeroPad = function (num, places) {
186 | const zero = places - num.toString().length + 1
187 | return Array(+(zero > 0 && zero)).join('0') + num
188 | }
189 |
190 | exports.formatTime = function (date) {
191 | if (!date) {
192 | date = new Date()
193 | } else if (!(date instanceof Date)) {
194 | date = new Date(date)
195 | }
196 | const year = date.getFullYear()
197 | const month = date.getMonth() + 1
198 | const day = date.getDate()
199 | const hour = date.getHours()
200 | const minute = date.getMinutes()
201 | return `${year}-${exports.zeroPad(month, 2)}-${exports.zeroPad(day, 2)} ${exports.zeroPad(hour, 2)}:${exports.zeroPad(minute, 2)}`
202 | }
203 |
204 | exports.isEmptyObject = function (obj) {
205 | if (obj == null) {
206 | return true
207 | }
208 | for (const key in obj) {
209 | if (obj.hasOwnProperty(key)) {
210 | return false
211 | }
212 | }
213 | return true
214 | }
215 |
216 | exports.urlJoin = function () {
217 | function normalize (str) {
218 | return str
219 | .replace(/([/]+)/g, '/')
220 | .replace(/\/\?(?!\?)/g, '?')
221 | .replace(/\/#/g, '#')
222 | .replace(/:\//g, '://')
223 | }
224 |
225 | const joined = [].slice.call(arguments, 0).join('/')
226 | return normalize(joined)
227 | }
228 |
--------------------------------------------------------------------------------
/src/util/open.js:
--------------------------------------------------------------------------------
1 | const exec = require('child_process').exec
2 |
3 | module.exports = function open (target, appName, callback) {
4 | let opener
5 |
6 | if (typeof (appName) === 'function') {
7 | callback = appName
8 | appName = null
9 | }
10 |
11 | switch (process.platform) {
12 | case 'darwin':
13 | if (appName) {
14 | opener = 'open -a "' + escape(appName) + '"'
15 | } else {
16 | opener = 'open'
17 | }
18 | break
19 | case 'win32':
20 | if (appName) {
21 | opener = 'start "" "' + escape(appName) + '"'
22 | } else {
23 | opener = 'start ""'
24 | }
25 | break
26 | default:
27 | if (appName) {
28 | opener = 'xdg-open "" "' + escape(appName) + '"'
29 | } else {
30 | opener = 'xdg-open ""'
31 | }
32 | break
33 | }
34 |
35 | if (process.env.SUDO_USER) {
36 | opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener
37 | }
38 | return exec(opener + ' "' + escape(target) + '"', callback)
39 | }
40 |
41 | function escape (s) {
42 | return s.replace(/"/g, '\\"')
43 | }
44 |
--------------------------------------------------------------------------------
/templates/complete/app/app-conf:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | app: '<%= appName %>',
3 | appId: '<%= appId %>',
4 | description: '<%= description %>',
5 | createTime: '<%= date %>',
6 | template: '<%= template %>',
7 | platform: '<%= platform %>',
8 | framework: '<%= framework %>',
9 | common: 'common',
10 | moduleList: ['common'],
11 | sass: '<%= sass %>'
12 | }
13 |
--------------------------------------------------------------------------------
/templates/complete/app/config/dev:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // environment variables
3 | env: {
4 | NODE_ENV: '"development"'
5 | },
6 | // define global constants for application see https://webpack.js.org/plugins/define-plugin/
7 | defineConstants: {
8 | },
9 | // dev server port
10 | port: 3000,
11 | // dev server host
12 | host: '0.0.0.0',
13 | // dev server protocol, support https
14 | protocol: 'http'
15 | }
16 |
--------------------------------------------------------------------------------
/templates/complete/app/config/index:
--------------------------------------------------------------------------------
1 | const config = {
2 | // source files root directory
3 | sourceRoot: 'src',
4 | // output files root directory
5 | outputRoot: 'dist',
6 | // The publicPath specifies the public URL address of the output files when referenced in a browser
7 | // see https://webpack.js.org/guides/public-path/
8 | publicPath: '/',
9 | // the directory contains css/js/images/fonts/media etc. files
10 | staticDirectory: 'static',
11 | // define global constants for application see https://webpack.js.org/plugins/define-plugin/
12 | defineConstants: {
13 | },
14 | // support functions
15 | module: {
16 | postcss: {
17 | // autoprefixer plugin config
18 | autoprefixer: {
19 | enable: true
20 | }
21 | }
22 | }
23 | }
24 |
25 | module.exports = function (merge) {
26 | if (process.env.NODE_ENV === 'development') {
27 | return merge({}, config, require('./dev'))
28 | }
29 | return merge({}, config, require('./prod'))
30 | }
31 |
--------------------------------------------------------------------------------
/templates/complete/app/config/prod:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // environment variables
3 | env: {
4 | NODE_ENV: '"production"'
5 | },
6 | // define global constants for application see https://webpack.js.org/plugins/define-plugin/
7 | defineConstants: {
8 | },
9 | pubish: {
10 | mode: 'sftp',
11 | host: 'labs.qiang.it',
12 | user: 'labs',
13 | pass: 'labslabslabs',
14 | port: 22,
15 | localPath: '/dist/',
16 | remotePath: '/usr/share/nginx/html/public/labs/' // required
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/templates/complete/app/editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/templates/complete/app/eslintconfig:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ['standard'<%- (framework === "nerv" || framework === "react") ? ", 'standard-jsx'" : "" %>],
4 | parser: 'babel-eslint',
5 | env: {
6 | browser: true
7 | },
8 | parserOptions: {
9 | sourceType: 'module'<% if (framework === "nerv" || framework === "react") { %>,
10 | ecmaFeatures: {
11 | 'jsx': true
12 | }<% } %>
13 | },
14 | rules: {
15 | // allow paren-less arrow functions
16 | 'arrow-parens': 0,
17 | // allow async-await
18 | 'generator-star-spacing': 0,
19 | // allow debugger during development
20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/templates/complete/app/gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .git/
3 | .cache/
4 |
--------------------------------------------------------------------------------
/templates/complete/app/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const path = require('path')
3 | const chalk = require('chalk')
4 | const shelljs = require('shelljs')
5 | const ora = require('ora')
6 | const uuid = require('uuid')
7 |
8 | module.exports = function create (creater, params, helper, cb) {
9 | const { appName, appId, description, framework, template, date, platform, sass } = params
10 | const commonDir = 'common'
11 | const sourceRootDir = 'src'
12 | const configDir = 'config'
13 | const configDirPath = path.join(appName, configDir)
14 | const sourceRootPath = path.join(appName, sourceRootDir)
15 | // create app dir
16 | fs.mkdirpSync(appName)
17 | fs.mkdirpSync(sourceRootPath)
18 | fs.mkdirpSync(configDirPath)
19 | fs.mkdirpSync(path.join(sourceRootPath, commonDir))
20 | fs.mkdirpSync(path.join(sourceRootPath, commonDir, 'page'))
21 | fs.mkdirpSync(path.join(sourceRootPath, commonDir, 'component'))
22 |
23 | // copy files
24 | creater.template(template, 'app', path.join(configDir, 'index'), path.join(configDirPath, 'index.js'))
25 | creater.template(template, 'app', path.join(configDir, 'dev'), path.join(configDirPath, 'dev.js'))
26 | creater.template(template, 'app', path.join(configDir, 'prod'), path.join(configDirPath, 'prod.js'))
27 | creater.template(template, 'module', 'mod-conf', path.join(sourceRootPath, commonDir, 'mod.conf.js'), {
28 | moduleName: commonDir,
29 | moduleId: uuid.v1(),
30 | date,
31 | appName,
32 | description: 'common module',
33 | common: commonDir
34 | })
35 | creater.template(template, 'app', 'editorconfig', path.join(appName, '.editorconfig'))
36 | creater.template(template, 'app', 'gitignore', path.join(appName, '.gitignore'))
37 | creater.template(template, 'app', 'jsconfigjson', path.join(appName, 'jsconfig.json'))
38 | creater.template(template, 'app', 'eslintconfig', path.join(appName, '.eslintrc.js'), {
39 | appName,
40 | framework,
41 | date
42 | })
43 | creater.template(template, 'app', 'packagejson', path.join(appName, 'package.json'), {
44 | appName,
45 | framework,
46 | date
47 | })
48 | creater.template(template, 'app', 'app-conf', path.join(appName, 'app.conf.js'), {
49 | appName,
50 | appId,
51 | platform,
52 | description,
53 | framework,
54 | template,
55 | date,
56 | sass
57 | })
58 |
59 | creater.fs.commit(() => {
60 | console.log()
61 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created app: ${chalk.grey.bold(appName)}`)}`)
62 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created directory: ${appName}/${configDir}`)}`)
63 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created directory: ${appName}/${commonDir}`)}`)
64 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created directory: ${appName}/${commonDir}/page`)}`)
65 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created directory: ${appName}/${commonDir}/component`)}`)
66 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/${configDir}/index.js`)}`)
67 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/${configDir}/dev.js`)}`)
68 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/${configDir}/prod.js`)}`)
69 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/${commonDir}/mod.conf.js`)}`)
70 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/.editorconfig`)}`)
71 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/.gitignore`)}`)
72 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/.eslintrc.js`)}`)
73 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/package.json`)}`)
74 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/jsconfig.json`)}`)
75 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${appName}/app.conf.js`)}`)
76 | console.log()
77 | const gitInitSpinner = ora(`cd ${chalk.cyan.bold(appName)}, executing ${chalk.cyan.bold('git init')}`).start()
78 | process.chdir(appName)
79 | const gitInit = shelljs.exec('git init', { silent: true })
80 | if (gitInit.code === 0) {
81 | gitInitSpinner.color = 'green'
82 | gitInitSpinner.succeed(gitInit.stdout)
83 | } else {
84 | gitInitSpinner.color = 'red'
85 | gitInitSpinner.fail(gitInit.stderr)
86 | }
87 | // install
88 | let command
89 | if (helper.shouldUseYarn()) {
90 | command = 'yarn install'
91 | } else if (helper.shouldUseCnpm()) {
92 | command = 'cnpm install'
93 | } else {
94 | command = 'npm install'
95 | }
96 | const installSpinner = ora(`Executing ${chalk.cyan.bold(command)}, it will take some time...`).start()
97 | const install = shelljs.exec(command, { silent: true })
98 | if (install.code === 0) {
99 | installSpinner.color = 'green'
100 | installSpinner.succeed('Install success')
101 | console.log(`${install.stderr}${install.stdout}`)
102 | } else {
103 | installSpinner.color = 'red'
104 | installSpinner.fail(chalk.red('Install dependencies failed! Please cd in the app directory install yourself!'))
105 | console.log(`${install.stderr}${install.stdout}`)
106 | }
107 | console.log(chalk.green(`Create app ${chalk.green.bold(appName)} Successfully!`))
108 | console.log(chalk.green(`Please cd ${chalk.green.bold(appName)} and start to work!😝`))
109 | if (typeof cb === 'function') {
110 | cb()
111 | }
112 | })
113 | }
114 |
--------------------------------------------------------------------------------
/templates/complete/app/jsconfigjson:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/templates/complete/app/packagejson:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= appName %>",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "test": "",
7 | "lint": "eslint ./src/",
8 | "lint:fix": "eslint ./src/ --fix",
9 | "precommit": "lint-staged"
10 | },
11 | "lint-staged": {
12 | "*.js": [
13 | "eslint --fix",
14 | "git add"
15 | ]
16 | },
17 | "dependencies": {<% if (framework === 'nerv') { %>
18 | "nervjs": "^1.2.8"<% } else if (framework === 'react') { %>
19 | "react": "^16.2.0",
20 | "react-dom": "^16.2.0"<% } else if (framework === 'vue') { %>
21 | "vue": "^2.5.13",
22 | "vue-router": "^3.0.1"<% } %>
23 | },
24 | "devDependencies": {
25 | "babel-eslint": "^8.2.1",
26 | "eslint": "^4.16.0",
27 | "eslint-config-standard": "^10.2.1",<% if (framework === "nerv" || framework === "react") { %>
28 | "eslint-config-standard-jsx": "^4.0.2",<%}%>
29 | "eslint-plugin-import": "^2.7.0",
30 | "eslint-plugin-node": "^5.1.1",
31 | "eslint-plugin-promise": "^3.5.0",<% if (framework === "nerv" || framework === "react") { %>
32 | "eslint-plugin-react": "^7.3.0",<%}%>
33 | "eslint-plugin-standard": "^3.0.1",
34 | "husky": "^0.14.3",
35 | "lint-staged": "^6.0.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/templates/complete/component/component.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
--------------------------------------------------------------------------------
/templates/complete/component/index.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash')
2 | const fs = require('fs-extra')
3 | const path = require('path')
4 | const chalk = require('chalk')
5 | const shelljs = require('shelljs')
6 | const ora = require('ora')
7 | const uuid = require('uuid')
8 |
9 | module.exports = function create (creater, params, helper, cb) {
10 | const { appName, template, framework, componentName, description, date, sass } = params
11 | // create component dir
12 | const componentDir = 'component'
13 | const componentCss = sass ? `${componentName}.scss` : `${componentName}.css`
14 |
15 | fs.mkdirpSync(path.join(componentDir, componentName))
16 |
17 | // copy files
18 | if (framework !== 'vue') {
19 | creater.template(template, 'component', 'component.css', path.join(componentDir, componentName, componentCss))
20 | creater.template(template, `component/${framework}`, 'component.js', path.join(componentDir, componentName, `${componentName}.js`), {
21 | date,
22 | description,
23 | componentName,
24 | sass
25 | })
26 | } else {
27 | creater.template(template, 'component/vue', 'component.vue', path.join(componentDir, componentName, `${componentName}.vue`), {
28 | componentName,
29 | sass
30 | })
31 | }
32 |
33 | creater.fs.commit(() => {
34 | console.log()
35 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created component: ${chalk.grey.bold(componentName)}`)}`)
36 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created directory: ${componentDir}/${componentName}`)}`)
37 | if (framework !== 'vue') {
38 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${componentDir}/${componentName}/${componentCss}`)}`)
39 | } else {
40 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${componentDir}/${componentName}/${componentName}.vue`)}`)
41 | }
42 | console.log(`${chalk.green('✔ ')}${chalk.grey(`Created file: ${componentDir}/${componentName}/${componentName}.js`)}`)
43 | console.log()
44 | console.log(chalk.green(`Create component ${chalk.green.bold(componentName)} Successfully!`))
45 | if (typeof cb === 'function') {
46 | cb()
47 | }
48 | })
49 | }
50 |
--------------------------------------------------------------------------------
/templates/complete/component/nerv/component.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author <%= username %>
3 | * @date <%= date %>
4 | * @desc <%= description %>
5 | */
6 |
7 | import Nerv from 'nervjs'
8 |
9 | import '<% if (sass) { %>./<%= componentName %>.scss<% } else { %><%= componentName %>.css<%}%>'
10 |
11 | class <%= _.upperFirst(_.camelCase(componentName)) %> extends Nerv.Component {
12 | constructor () {
13 | super(...arguments)
14 | this.state = {}
15 | }
16 |
17 | render () {
18 | return (
19 |