├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── assets ├── chrome01.png ├── firefox01.png ├── firefox02.png ├── firefox03.png ├── firefox04.png ├── icon.png ├── safari01.png ├── safari02.png ├── safari03.png └── safari04.png ├── bin.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | tmp/ 4 | dist/ 5 | npm-debug.log* 6 | .DS_Store 7 | .nyc_output 8 | tmp/ 9 | package-lock.json 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "8" 3 | - "9" 4 | sudo: false 5 | language: node_js 6 | script: "npm run test" 7 | # after_success: "npm i -g codecov && npm run coverage && codecov" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yoshua Wuyts 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # create-choo-app [![stability][0]][1] 2 | [![npm version][2]][3] [![build status][4]][5] 3 | [![downloads][8]][9] [![js-standard-style][10]][11] 4 | 5 | Create a fresh choo application. Because starting a new project should take 6 | minutes, not days. 7 | 8 | ## Usage 9 | ```sh 10 | $ npx create-choo-app 11 | ``` 12 | 13 | ## ⚠️ HTTPS Instructions 14 | When you first open up your application in a browser, you'll probably see a 15 | warning page about HTTPS connections being untrusted. No worries, this is 16 | entirely expected behavior. Follow the instructions below to solve this for 17 | your browser. 18 | 19 |
20 | 21 | How does this work? 22 | 23 | For HTTPS to run on localhost, we must sign a TLS certificate 24 | locally. This is better known as a "self-signed certificate". Browsers 25 | actively check for certificates from unknown providers, and warn you (for good 26 | reason!) In our case, however, it's safe to ignore. 27 | 28 | HTTPS is needed for an increasing amount of APIs to work in the browser. For 29 | example if you want to test HTTP/2 connections or use parts of the storage 30 | API, you have no choice but to use an HTTPS connection on localhost. That's 31 | why we try and make this work as efficiently, and securely as possible. 32 | 33 | We generate a unique certificate for each Bankai installation at 34 | ~/.config/bankai. This means that you'll only need to trust an 35 | HTTPS certificate for Bankai once. This should be secure from remote 36 | attackers, because unless they have successfully acquired access to your 37 | machine's filesystem, they won't be able to replicate the certificate. 38 |
39 | 40 |
41 | 42 | Firefox Instructions 43 | 44 |

Step 1

45 | 46 | A wild security screen appears!. Click on "advanced". 47 | firefox01 48 | 49 |

Step 2

50 | More details emerge! Click on "Add Exception". 51 | firefox02 52 | 53 |

Step 3

54 | In the dropdown click "Confirm Security Exception". 55 | firefox03 56 | 57 |

Step 4

58 | Success! 59 | firefox04 60 |
61 | 62 |
63 | 64 | Chrome Instructions 65 | 66 | Click the "more details" dropdown, then click "proceed". 67 | chrome01 68 |
69 | 70 |
71 | 72 | Safari Instructions 73 | 74 |

Step 1

75 | A wild security screen appears! Click "Show Certificate". 76 | safari01 77 | 78 |

Step 2

79 | More details emerge! Check "Always trust 'localhost'…". 80 | safari02 81 | 82 |

Step 3

83 | The box is checked! Click "Continue". 84 | safari03 85 | 86 |

Step 4

87 | A box is asking you for your crendentials. Fill them in, and hit "Enter". 88 | 89 |

Step 5

90 | Success! 91 | safari04 92 |
93 | 94 | ## Dependencies 95 | `create-choo-app` installs the following dependencies: 96 | 97 | Name | Dependency Type | Description | 98 | ---------------------------------------------------------------------|-----------------|-------------| 99 | [choo](https://github.com/choojs/choo) | Production | Fast, 4kb framework. 100 | [choo-service-worker](https://github.com/choojs/choo-service-worker) | Production | Offline support for Choo. 101 | [sheetify](https://github.com/stackcss/sheetify/) | Production | Hyper performant CSS-in-JS. 102 | [tachyons](http://tachyons.io/) | Production | A minimalist CSS toolkit. 103 | [bankai](https://github.com/choojs/bankai) | Development | An asset bundler and static file server. 104 | [choo-devtools](https://github.com/choojs/choo-devtools) | Development | Debug Choo applications. 105 | [choo-scaffold](https://github.com/choojs/choo-scaffold) | Development | Generate new application files. 106 | [dependency-check](https://github.com/maxogden/dependency-check) | Development | Verify project dependencies. 107 | [standard](https://standardjs.com/) | Development | Statically check JavaScript files for errors. 108 | 109 | ## Removing Dependencies 110 | 111 | If you want to remove Tachyons you can do so by running `npm uninstall tachyons` and removing the reference to Tachyons in `./index.js`. 112 | 113 | ## API 114 | ```txt 115 | $ create-choo-app [options] 116 | 117 | Options: 118 | 119 | -h, --help print usage 120 | -v, --version print version 121 | -q, --quiet don't output any logs 122 | 123 | Examples: 124 | 125 | Create a new Choo application 126 | $ create-choo-app 127 | 128 | Running into trouble? Feel free to file an issue: 129 | https://github.com/choojs/create-choo-app/issues/new 130 | 131 | Do you enjoy using this software? Become a backer: 132 | https://opencollective.com/choo 133 | ``` 134 | 135 | See the generated output [here](https://github.com/perguth/create-choo-app). 136 | 137 | ## License 138 | [MIT](https://tldrlegal.com/license/mit-license) 139 | 140 | [0]: https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square 141 | [1]: https://nodejs.org/api/documentation.html#documentation_stability_index 142 | [2]: https://img.shields.io/npm/v/create-choo-app.svg?style=flat-square 143 | [3]: https://npmjs.org/package/create-choo-app 144 | [4]: https://img.shields.io/travis/choojs/create-choo-app/master.svg?style=flat-square 145 | [5]: https://travis-ci.org/choojs/create-choo-app 146 | [6]: https://img.shields.io/codecov/c/github/choojs/create-choo-app/master.svg?style=flat-square 147 | [7]: https://codecov.io/github/choojs/create-choo-app 148 | [8]: http://img.shields.io/npm/dm/create-choo-app.svg?style=flat-square 149 | [9]: https://npmjs.org/package/create-choo-app 150 | [10]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 151 | [11]: https://github.com/feross/standard 152 | -------------------------------------------------------------------------------- /assets/chrome01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/chrome01.png -------------------------------------------------------------------------------- /assets/firefox01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/firefox01.png -------------------------------------------------------------------------------- /assets/firefox02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/firefox02.png -------------------------------------------------------------------------------- /assets/firefox03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/firefox03.png -------------------------------------------------------------------------------- /assets/firefox04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/firefox04.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/icon.png -------------------------------------------------------------------------------- /assets/safari01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/safari01.png -------------------------------------------------------------------------------- /assets/safari02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/safari02.png -------------------------------------------------------------------------------- /assets/safari03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/safari03.png -------------------------------------------------------------------------------- /assets/safari04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/choojs/create-choo-app/d2ae30a7abf7f018d09b4cd47d46c35b98ce6e30/assets/safari04.png -------------------------------------------------------------------------------- /bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var mapLimit = require('async-collection/map-limit') 4 | var series = require('async-collection/series') 5 | var ansi = require('ansi-escape-sequences') 6 | var inquirer = require('inquirer') 7 | var minimist = require('minimist') 8 | var dedent = require('dedent') 9 | var rimraf = require('rimraf') 10 | var path = require('path') 11 | 12 | var lib = require('./') 13 | 14 | var TRAIN = '🚂🚋🚋' 15 | 16 | var USAGE = ` 17 | $ ${clr('create-choo-app', 'bold')} ${clr('', 'green')} [options] 18 | 19 | Options: 20 | 21 | -h, --help print usage 22 | -v, --version print version 23 | -q, --quiet don't output any logs 24 | 25 | Examples: 26 | 27 | Create a new Choo application 28 | ${clr('$ create-choo-app', 'cyan')} 29 | 30 | Running into trouble? Feel free to file an issue: 31 | ${clr('https://github.com/choojs/create-choo-app/issues/new', 'cyan')} 32 | 33 | Do you enjoy using this software? Become a backer: 34 | ${clr('https://opencollective.com/choo', 'cyan')} 35 | `.replace(/\n$/, '').replace(/^\n/, '') 36 | 37 | var NODIR = ` 38 | Please specify the project directory: 39 | ${clr('$ create-choo-app', 'cyan')} ${clr('', 'green')} 40 | 41 | For example: 42 | ${clr('$ create-choo-app', 'cyan')} ${clr('my-choo-app', 'green')} 43 | 44 | Run ${clr('create-choo-app --help', 'cyan')} to see all options. 45 | `.replace(/\n$/, '').replace(/^\n/, '') 46 | 47 | var argv = minimist(process.argv.slice(2), { 48 | alias: { 49 | help: 'h', 50 | quiet: 'q', 51 | version: 'v' 52 | }, 53 | boolean: [ 54 | 'help', 55 | 'quiet', 56 | 'version' 57 | ] 58 | }) 59 | 60 | ;(function main (argv) { 61 | var dir = argv._[0] 62 | var description = argv._[1] 63 | 64 | if (argv.help) { 65 | console.log(USAGE) 66 | } else if (argv.version) { 67 | console.log(require('./package.json').version) 68 | } else if (!dir) { 69 | console.log(NODIR) 70 | process.exit(1) 71 | } else { 72 | create(path.join(process.cwd(), dir), description, argv) 73 | } 74 | })(argv) 75 | 76 | async function create (dir, description, argv) { 77 | var written = [] 78 | var cmds = [ 79 | function (done) { 80 | print('Creating a new Choo app in ' + clr(dir, 'green') + '.\n') 81 | lib.mkdir(dir, done) 82 | }, 83 | function (done) { 84 | var filename = 'package.json' 85 | printFile(filename) 86 | written.push(path.join(dir, filename)) 87 | lib.writePackage(dir, done) 88 | }, 89 | function (done) { 90 | print('\nInstalling packages, this might take a couple of minutes.') 91 | written.push(path.join(dir, 'node_modules')) 92 | var pkgs = [ 93 | 'choo', 94 | 'choo-service-worker', 95 | 'sheetify', 96 | 'tachyons' 97 | ] 98 | var msg = clrInstall(pkgs) 99 | print('Installing ' + msg + '…') 100 | lib.install(dir, pkgs, done) 101 | }, 102 | function (done) { 103 | var pkgs = [ 104 | 'bankai', 105 | 'choo-devtools', 106 | 'choo-scaffold', 107 | 'dependency-check', 108 | 'standard' 109 | ] 110 | var msg = clrInstall(pkgs) 111 | print('Installing ' + msg + '…') 112 | lib.devInstall(dir, pkgs, done) 113 | }, 114 | function (done) { 115 | print('') 116 | var filename = '.gitignore' 117 | printFile(filename) 118 | written.push(path.join(dir, filename)) 119 | lib.writeIgnore(dir, done) 120 | }, 121 | function (done) { 122 | var filename = 'README.md' 123 | printFile(filename) 124 | written.push(path.join(dir, filename)) 125 | lib.writeReadme(dir, description, done) 126 | }, 127 | function (done) { 128 | var filename = 'index.js' 129 | printFile(filename) 130 | written.push(path.join(dir, filename)) 131 | lib.writeIndex(dir, done) 132 | }, 133 | function (done) { 134 | var filename = 'stores/clicks.js' 135 | printFile(filename) 136 | written.push(path.join(dir, filename)) 137 | lib.writeStore(dir, done) 138 | }, 139 | function (done) { 140 | var filename = 'sw.js' 141 | printFile(filename) 142 | written.push(path.join(dir, filename)) 143 | lib.writeServiceWorker(dir, done) 144 | }, 145 | function (done) { 146 | var filename = 'views/main.js' 147 | printFile(filename) 148 | written.push(path.join(dir, filename)) 149 | lib.writeMainView(dir, done) 150 | }, 151 | function (done) { 152 | var filename = 'views/404.js' 153 | printFile(filename) 154 | written.push(path.join(dir, filename)) 155 | lib.writeNotFoundView(dir, done) 156 | }, 157 | function (done) { 158 | var filename = 'manifest.json' 159 | printFile(filename) 160 | written.push(path.join(dir, filename)) 161 | lib.writeManifest(dir, description, done) 162 | }, 163 | function (done) { 164 | var filename = 'assets/icon.png' 165 | printFile(filename) 166 | written.push(path.join(dir, filename)) 167 | lib.writeIcon(dir, done) 168 | }, 169 | function (done) { 170 | var message = '.' 171 | print('\nInitializing ' + clr('git', 'cyan')) 172 | written.push(path.join(dir, '.git')) 173 | lib.createGit(dir, message, done) 174 | } 175 | ] 176 | 177 | if (!description) { 178 | var answers = await inquirer.prompt([ 179 | { 180 | type: 'input', 181 | name: 'description', 182 | message: "What's the purpose of your project? (This is used in the readme & web app manifest.)\n>" 183 | } 184 | ]) 185 | description = answers.description 186 | } 187 | 188 | series(cmds, function (err) { 189 | if (err) { 190 | print('\nAborting installation. The following error occured:') 191 | print(' ' + clr(err.message, 'red') + '\n') 192 | mapLimit(written, 1, cleanFile, function (err) { 193 | if (err) throw err 194 | console.log('Cleanup completed, please try again sometime.') 195 | process.exit(1) 196 | }) 197 | } else { 198 | var msg = dedent` 199 | App created in ${clr(dir, 'green')}. 200 | ${clr('All done, good job!', 'magenta')} ${TRAIN} 201 | 202 | The following commands are available: 203 | ${clr('npm start', 'cyan')} Start the development server 204 | ${clr('npm test', 'cyan')} Lint, validate deps & run tests 205 | ${clr('npm run build', 'cyan')} Compile all files to ${clr('dist/', 'green')} 206 | ${clr('npm run inspect', 'cyan')} Inspect the bundle dependencies 207 | 208 | Do you enjoy using this software? Become a backer: 209 | ${clr('https://opencollective.com/choo', 'cyan')} 210 | `.replace(/\n$/g, '') 211 | print('\n' + msg) 212 | } 213 | }) 214 | 215 | function print (val) { 216 | if (!argv.quiet) console.log(val) 217 | } 218 | 219 | function printFile (filename) { 220 | print('Creating file ' + clr(filename, 'cyan') + '…') 221 | } 222 | } 223 | 224 | function clr (text, color) { 225 | return process.stdout.isTTY ? ansi.format(text, color) : text 226 | } 227 | 228 | function clrInstall (pkgs) { 229 | return pkgs.reduce(function (str, pkg, i) { 230 | pkg = clr(pkg, 'cyan') 231 | if (i === pkgs.length - 1) { 232 | return str + pkg 233 | } else if (i === pkgs.length - 2) { 234 | return str + pkg + ', and ' 235 | } else { 236 | return str + pkg + ', ' 237 | } 238 | }, '') 239 | } 240 | 241 | function cleanFile (file, cb) { 242 | console.log('Deleting generated file… ' + clr(path.basename(file), 'cyan')) 243 | rimraf(file, cb) 244 | } 245 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var exec = require('child_process').exec 2 | var dedent = require('dedent') 3 | var mkdirp = require('mkdirp') 4 | var path = require('path') 5 | var pump = require('pump') 6 | var fs = require('fs') 7 | 8 | exports.mkdir = function (dir, cb) { 9 | mkdirp(dir, function (err) { 10 | if (err) return cb(new Error('Could not create directory ' + dir)) 11 | fs.readdir(dir, function (err, files) { 12 | if (err) return cb(new Error('Could not read directory ' + dir)) 13 | if (files.length) return cb(new Error('Directory contains files. This might create conflicts.')) 14 | cb() 15 | }) 16 | }) 17 | } 18 | 19 | exports.writePackage = function (dir, cb) { 20 | var filename = path.join(dir, 'package.json') 21 | var name = path.basename(dir) 22 | var file = dedent` 23 | { 24 | "name": "${name}", 25 | "version": "1.0.0", 26 | "private": true, 27 | "scripts": { 28 | "build": "bankai build index.js", 29 | "create": "choo-scaffold", 30 | "inspect": "bankai inspect index.js", 31 | "start": "bankai start index.js", 32 | "test": "standard && npm run test-deps", 33 | "test-deps": "dependency-check . && dependency-check . --extra --no-dev -i tachyons" 34 | } 35 | } 36 | ` 37 | write(filename, file, cb) 38 | } 39 | 40 | exports.writeIgnore = function (dir, cb) { 41 | var filename = path.join(dir, '.gitignore') 42 | var file = dedent` 43 | node_modules/ 44 | .nyc_output/ 45 | coverage/ 46 | dist/ 47 | tmp/ 48 | npm-debug.log* 49 | .DS_Store 50 | ` 51 | 52 | write(filename, file, cb) 53 | } 54 | 55 | exports.writeReadme = function (dir, description, cb) { 56 | var filename = path.join(dir, 'README.md') 57 | var name = path.basename(dir) 58 | var file = dedent` 59 | # ${name} 60 | ${description} 61 | 62 | ## Commands 63 | Command | Description | 64 | -----------------------|--------------------------------------------------| 65 | \`$ npm start\` | Start the development server 66 | \`$ npm test\` | Lint, validate deps & run tests 67 | \`$ npm run build\` | Compile all files into \`dist/\` 68 | \`$ npm run create\` | Generate a scaffold file 69 | \`$ npm run inspect\` | Inspect the bundle's dependencies 70 | ` 71 | 72 | write(filename, file, cb) 73 | } 74 | 75 | exports.writeIndex = function (dir, cb) { 76 | var filename = path.join(dir, 'index.js') 77 | var file = dedent` 78 | var css = require('sheetify') 79 | var choo = require('choo') 80 | 81 | css('tachyons') 82 | 83 | var app = choo() 84 | if (process.env.NODE_ENV !== 'production') { 85 | app.use(require('choo-devtools')()) 86 | } else { 87 | app.use(require('choo-service-worker')()) 88 | } 89 | 90 | app.use(require('./stores/clicks')) 91 | 92 | app.route('/', require('./views/main')) 93 | app.route('/*', require('./views/404')) 94 | 95 | module.exports = app.mount('body')\n 96 | ` 97 | 98 | write(filename, file, cb) 99 | } 100 | 101 | exports.writeServiceWorker = function (dir, cb) { 102 | var filename = path.join(dir, 'sw.js') 103 | var file = dedent` 104 | /* eslint-env serviceworker */ 105 | 106 | var VERSION = require('./package.json').version 107 | var URLS = process.env.FILE_LIST 108 | 109 | // Respond with cached resources 110 | self.addEventListener('fetch', function (e) { 111 | e.respondWith(self.caches.match(e.request).then(function (request) { 112 | if (request) return request 113 | else return self.fetch(e.request) 114 | })) 115 | }) 116 | 117 | // Register worker 118 | self.addEventListener('install', function (e) { 119 | e.waitUntil(self.caches.open(VERSION).then(function (cache) { 120 | return cache.addAll(URLS) 121 | })) 122 | }) 123 | 124 | // Remove outdated resources 125 | self.addEventListener('activate', function (e) { 126 | e.waitUntil(self.caches.keys().then(function (keyList) { 127 | return Promise.all(keyList.map(function (key, i) { 128 | if (keyList[i] !== VERSION) return self.caches.delete(keyList[i]) 129 | })) 130 | })) 131 | })\n 132 | ` 133 | 134 | write(filename, file, cb) 135 | } 136 | 137 | exports.writeManifest = function (dir, description, cb) { 138 | var filename = path.join(dir, 'manifest.json') 139 | var name = path.basename(dir) 140 | var file = dedent` 141 | { 142 | "name": "${name}", 143 | "short_name": "${name}", 144 | "description": "${description}", 145 | "start_url": "/", 146 | "display": "standalone", 147 | "background_color": "#000", 148 | "theme_color": "#000", 149 | "icons": [{ 150 | "src": "/assets/icon.png", 151 | "type": "image/png", 152 | "sizes": "512x512" 153 | }] 154 | } 155 | ` 156 | 157 | write(filename, file, cb) 158 | } 159 | 160 | exports.writeNotFoundView = function (dir, cb) { 161 | var dirname = path.join(dir, 'views') 162 | var filename = path.join(dirname, '404.js') 163 | var projectname = path.basename(dir) 164 | var file = dedent` 165 | var html = require('choo/html') 166 | 167 | var TITLE = '${projectname} - route not found' 168 | 169 | module.exports = view 170 | 171 | function view (state, emit) { 172 | if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE) 173 | return html\` 174 | 175 |

Route not found.

176 | Back to main. 177 | 178 | \` 179 | }\n 180 | ` 181 | 182 | mkdirp(dirname, function (err) { 183 | if (err) return cb(new Error('Could not create directory ' + dirname)) 184 | write(filename, file, cb) 185 | }) 186 | } 187 | 188 | exports.writeMainView = function (dir, cb) { 189 | var dirname = path.join(dir, 'views') 190 | var filename = path.join(dirname, 'main.js') 191 | var projectname = path.basename(dir) 192 | var file = dedent` 193 | var html = require('choo/html') 194 | 195 | var TITLE = '${projectname} - main' 196 | 197 | module.exports = view 198 | 199 | function view (state, emit) { 200 | if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE) 201 | 202 | return html\` 203 | 204 |
205 |
206 |

1.

207 |

208 | Welcome to your new Choo application. 209 | We're very happy you've made it this far. 210 |

211 | 212 |

213 | You're now in control of your own Choo app. The moment you decide to 214 | deploy it, it'll work offline and on any device. 215 |

216 | 217 |
218 |
219 | 220 |
221 |

2.

222 | 223 |

224 | We've outfitted your project with a small selection of commands to 225 | help you achieve results faster: 226 |

227 | 228 |
    229 |
  • 230 | npm start
    231 | start your project for local development. 232 |
  • 233 |
  • 234 | npm run build
    235 | compile your project for production. 236 |
  • 237 |
  • 238 | npm run inspect
    239 | visualize your project's dependencies. 240 |
  • 241 |
  • 242 | npm run create
    243 | scaffold a new file. 244 |
  • 245 |
246 | 247 |
248 |
249 | 250 |
251 |

3.

252 | 253 |

254 | Your project also comes with a few directories. These names have 255 | special meanings for the build tool, so it's good to know what they 256 | do. 257 |

258 | 259 |
    260 |
  • 261 | assets/
    262 | Static files that can be served up, such as images and fonts. 263 |
  • 264 |
  • 265 | components/
    266 | Reusable fragments that can be composed into views. 267 |
  • 268 |
  • 269 | stores/
    270 | Pieces of logic that are shared by multiple components. 271 |
  • 272 |
  • 273 | views/
    274 | Combinations of components that are mapped to routes. 275 |
  • 276 |
277 | 278 |
279 |
280 | 281 |
282 |

4.

283 | 284 |

285 | So far we've provided you with one base view, one fallback view, and one store. This serves 287 | as an example. A place to start from. It's your project now, so 288 | go ahead and delete them once you know how they work. 289 |

290 | 291 |

Number of clicks stored: \${state.totalClicks}

292 | 293 | 297 | 298 |

299 |
300 | 301 |
302 |

5.

303 | 304 |

305 | To make your development journey more pleasant, we've also 306 | included devtools. If 308 | you open your browser console, here's a selection of the 309 | commands that are at your disposal: 310 | 311 |

    312 |
  • 313 | choo.state
    314 | Log the current application state. 315 |
  • 316 |
  • 317 | choo.log
    318 | Log the last 150 events received by the event bus. 319 |
  • 320 |
  • 321 | choo.emit
    322 | Emit an event inside the application event bus. 323 |
  • 324 |
  • 325 | choo.help
    326 | See an overview of all available commands. 327 |
  • 328 |
329 |

330 |
331 | 332 |
333 |

6.

334 | 335 |

336 | And that's about it! Thanks for reading. If you have any 337 | questions, check out the docs or reach 338 | out on GitHub or IRC. 340 | We're online everyday, and always around to help. Happy hacking! 341 |

342 |
343 |
344 | 345 | \` 346 | 347 | function handleClick () { 348 | emit('clicks:add', 1) 349 | } 350 | }\n 351 | ` 352 | file = file.replace(/\\\$/g, '$') 353 | 354 | mkdirp(dirname, function (err) { 355 | if (err) return cb(new Error('Could not create directory ' + dirname)) 356 | write(filename, file, cb) 357 | }) 358 | } 359 | 360 | exports.writeIcon = function (dir, cb) { 361 | var iconPath = path.join(__dirname, 'assets/icon.png') 362 | var dirname = path.join(dir, 'assets') 363 | var filename = path.join(dirname, 'icon.png') 364 | mkdirp(dirname, function (err) { 365 | if (err) return cb(new Error('Could not create directory ' + dirname)) 366 | var source = fs.createReadStream(iconPath) 367 | var sink = fs.createWriteStream(filename) 368 | pump(source, sink, function (err) { 369 | if (err) return cb(new Error('Could not write file ' + filename)) 370 | cb() 371 | }) 372 | }) 373 | } 374 | 375 | exports.writeStore = function (dir, cb) { 376 | var filename = path.join(dir, 'stores/clicks.js') 377 | var file = dedent` 378 | module.exports = store 379 | 380 | function store (state, emitter) { 381 | state.totalClicks = 0 382 | 383 | emitter.on('DOMContentLoaded', function () { 384 | emitter.on('clicks:add', function (count) { 385 | state.totalClicks += count 386 | emitter.emit(state.events.RENDER) 387 | }) 388 | }) 389 | }\n 390 | ` 391 | 392 | mkdirp(path.dirname(filename), function (err) { 393 | if (err) return cb(err) 394 | write(filename, file, cb) 395 | }) 396 | } 397 | 398 | exports.install = function (dir, packages, cb) { 399 | packages = packages.join(' ') 400 | var cmd = 'npm install --save --loglevel error ' + packages 401 | var popd = pushd(dir) 402 | exec(cmd, {env: process.env}, function (err) { 403 | if (err) return cb(new Error(cmd)) 404 | popd() 405 | cb() 406 | }) 407 | } 408 | 409 | exports.devInstall = function (dir, packages, cb) { 410 | packages = packages.join(' ') 411 | var cmd = 'npm install --save-dev --loglevel error ' + packages 412 | var popd = pushd(dir) 413 | exec(cmd, {env: process.env}, function (err) { 414 | if (err) return cb(new Error(cmd)) 415 | popd() 416 | cb() 417 | }) 418 | } 419 | 420 | exports.createGit = function (dir, message, cb) { 421 | var init = 'git init' 422 | var add = 'git add -A' 423 | var config = 'git config user.email' 424 | var commit = 'git commit -m "' + message + '"' 425 | 426 | var popd = pushd(dir) 427 | exec(init, function (err) { 428 | if (err) return cb(new Error(init)) 429 | 430 | exec(add, function (err) { 431 | if (err) return cb(new Error(add)) 432 | 433 | exec(config, function (err) { 434 | if (err) return cb(new Error(config)) 435 | 436 | exec(commit, function (err) { 437 | if (err) return cb(new Error(commit)) 438 | popd() 439 | cb() 440 | }) 441 | }) 442 | }) 443 | }) 444 | } 445 | 446 | function pushd (dir) { 447 | var prev = process.cwd() 448 | process.chdir(dir) 449 | return function popd () { 450 | process.chdir(prev) 451 | } 452 | } 453 | 454 | function write (filename, file, cb) { 455 | fs.writeFile(filename, file, function (err) { 456 | if (err) return cb(new Error('Could not write file ' + filename)) 457 | cb() 458 | }) 459 | } 460 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-choo-app", 3 | "description": "Create a fresh choo application", 4 | "repository": "choojs/create-choo-app", 5 | "version": "1.12.3", 6 | "bin": { 7 | "create-choo-app": "./bin.js" 8 | }, 9 | "scripts": { 10 | "deps": "dependency-check . && dependency-check . -i ./bin.js --extra --no-dev", 11 | "start": "node .", 12 | "test": "standard && npm run deps && npm run test-fast", 13 | "test-fast": "rm -rf tmp && ./bin.js tmp test" 14 | }, 15 | "dependencies": { 16 | "ansi-escape-sequences": "^3.0.0", 17 | "async-collection": "^1.0.1", 18 | "dedent": "^0.7.0", 19 | "inquirer": "^5.0.1", 20 | "minimist": "^1.2.0", 21 | "mkdirp": "^0.5.1", 22 | "pump": "^1.0.2", 23 | "rimraf": "^2.6.1" 24 | }, 25 | "devDependencies": { 26 | "dependency-check": "~2.6.0", 27 | "standard": "^10.0.2" 28 | }, 29 | "keywords": [ 30 | "generate", 31 | "choo", 32 | "create" 33 | ], 34 | "license": "MIT" 35 | } 36 | --------------------------------------------------------------------------------