├── .build ├── __app.js ├── index.html └── index.js ├── .gitignore ├── README.markdown ├── index.js ├── package.json ├── processFile.js ├── setupFs.js ├── surge.js └── watcher.js /.build/__app.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var ReactDOM = require('react-dom'); 3 | var AppRoot = require('../index'); 4 | 5 | ReactDOM.render( 6 | , 7 | document.getElementById('app') 8 | ); 9 | -------------------------------------------------------------------------------- /.build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.build/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brentvatne/resurge/50145ab90a2883803d7b78df053011ff315f9aa3/.build/index.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ``` 2 | ________ _______ ___________ ____ 3 | / ___/ _ \/ ___/ / / / ___/ __ `/ _ \ 4 | / / / __(__ ) /_/ / / / /_/ / __/ 5 | /_/ \___/____/\__,_/_/ \__, /\___/ 6 | /____/ 7 | ``` 8 | 9 | Make and share a small React project with minimal effort. In response to 10 | [@vjeux's fun challenge](https://twitter.com/Vjeux/status/680769537550102530). 11 | 12 | 1. `npm i resurge -g` 13 | 2. `mkdir your-project && cd your-project` 14 | 3. `touch index.js`, [add a React component](#sample-starter-app) and export it 15 | 4. Run `resurge` 16 | 17 | ### My project name is taken 18 | 19 | Rename the directory and try again? :p 20 | 21 | ### Commands 22 | 23 | - `resurge` will build and publish your app 24 | - `resurge --watch` will watch your directory for changes and publish 25 | them to surge automatically 26 | - `resurge --list` will show you apps you have deployed to surge.sh 27 | 28 | ### Can I use xyz? 29 | 30 | - Install any npm package you want. Your project will have react/react-dom by default. 31 | - This uses Babel/Browserfiy, with [stage-3](https://babeljs.io/docs/plugins/preset-stage-3/) and [react](http://babeljs.io/docs/plugins/preset-react/) plugins. 32 | 33 | ### Sample starter app 34 | 35 | ```javascript 36 | 'use strict'; 37 | var React = require('react'); 38 | 39 | class App extends React.Component { 40 | render() { 41 | return ( 42 |

Hello world

43 | ); 44 | } 45 | } 46 | 47 | module.exports = App; 48 | ``` 49 | 50 | ### Contribute 51 | 52 | - Feel free to contribute in any way you want as long as it doesn't make 53 | this project any more difficult to get into. Creating a new project 54 | and publishing it should never take more than the 4 simple steps 55 | described above. 56 | - You could make the CLI better, like this: 57 | https://github.com/sintaxi/harp/blob/ko-with-surge/bin/harp 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | const argv = require('yargs').argv; 5 | const surge = require('./surge'); 6 | const processFile = require('./processFile'); 7 | const fs = require('fs-extra'); 8 | const main = 'index.js'; 9 | const buildPath = `${process.cwd()}/.build`; 10 | 11 | if (argv.list) { 12 | surge.list(); 13 | } else { 14 | // Copy node_modules over, this sucks but babel doesn't support multiple 15 | // sourceRoots right now :( 16 | require('./setupFs')(); 17 | 18 | try { 19 | fs.statSync(main); 20 | } catch (err) { 21 | console.error(`Missing ${main} -- create it and have it export your root React component`); 22 | process.exit(1); 23 | } 24 | 25 | console.log('Running initial build...'); 26 | compileAndPublish(); 27 | 28 | if (argv.watch) { 29 | const watcher = require('./watcher')(); 30 | watcher.on('change', (path, stats) => { 31 | console.log(`${path} changed, compiling..`); 32 | compileAndPublish(); 33 | }); 34 | 35 | watcher.on('unlink', (path, stats) => { 36 | console.log(`${path} removed, compiling..`); 37 | compileAndPublish(); 38 | }); 39 | } 40 | } 41 | 42 | function compileAndPublish() { 43 | try { 44 | processFile('./.build/__app.js', `${buildPath}/${main}`).then((result) => { 45 | let pathParts = process.cwd().split('/'); 46 | let domain = 'resurge-' + pathParts[pathParts.length - 1] + '.surge.sh'; 47 | 48 | surge.publish({ 49 | project: buildPath, 50 | domain: domain, 51 | }); 52 | }); 53 | } catch(err) { 54 | console.log(err); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resurge", 3 | "version": "0.4.0", 4 | "description": "Instant React app setup and deploy with surge.sh", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "babel-core": "^6.3.26", 13 | "babel-preset-react": "^6.3.13", 14 | "babel-preset-stage-3": "^6.3.13", 15 | "babelify": "^7.2.0", 16 | "browserify": "^12.0.1", 17 | "chokidar": "^1.4.1", 18 | "fs-extra": "^0.26.3", 19 | "react": "^0.14.3", 20 | "react-dom": "^0.14.3", 21 | "surge": "^0.17.4", 22 | "yargs": "^3.31.0" 23 | }, 24 | "bin": { 25 | "resurge": "index.js" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /processFile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const browserify = require('browserify'); 5 | 6 | const config = { 7 | "presets": ["stage-3", "react"], 8 | }; 9 | 10 | function processFile(file, dest) { 11 | let result = fs.createWriteStream(dest); 12 | 13 | return new Promise((resolve, reject) => { 14 | browserify(file) 15 | .transform('babelify', config) 16 | .bundle() 17 | .on('error', (error) => { console.log(error.message) }) 18 | .on('data', (data) => { result.write(data) }) 19 | .on('end', () => { resolve('hiiiiii'); }); 20 | }); 21 | } 22 | 23 | module.exports = processFile; 24 | -------------------------------------------------------------------------------- /setupFs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs-extra'); 4 | 5 | module.exports = function() { 6 | const rootPath = __dirname; 7 | const rootNodeModulesPath = `${rootPath}/node_modules`; 8 | const projectPath = process.cwd(); 9 | const projectNodeModulesPath = `${projectPath}/node_modules`; 10 | 11 | const whitelist = [ 12 | 'babel-core', 13 | 'babel-preset-react', 14 | 'babel-preset-stage-3', 15 | 'react', 16 | 'react-dom', 17 | 'babelify', 18 | 'browserify', 19 | ]; 20 | 21 | fs.mkdirpSync(projectNodeModulesPath); 22 | whitelist.forEach((module) => { 23 | let source = `${rootNodeModulesPath}/${module}`; 24 | let destination = `${projectNodeModulesPath}/${module}`; 25 | 26 | if (!fs.existsSync(destination)) { 27 | try { 28 | fs.copySync(source, destination); 29 | } catch (err) { 30 | console.log(err.message); 31 | } 32 | }; 33 | }); 34 | 35 | 36 | const projectBuildPath = `${projectPath}/.build`; 37 | const templateBuildPath = `${rootPath}/.build`; 38 | fs.removeSync(projectBuildPath); 39 | fs.mkdirpSync(projectBuildPath); 40 | 41 | try { 42 | fs.copySync(`${templateBuildPath}/index.html`, `${projectBuildPath}/index.html`); 43 | fs.copySync(`${templateBuildPath}/__app.js`, `${projectBuildPath}/__app.js`); 44 | } catch(err) { 45 | console.log(err.message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /surge.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var spawn = require('child_process').spawn 4 | var path = require('path') 5 | var surge = path.resolve(path.dirname(require.resolve('surge')), '../../.bin/surge' + (process.platform === 'win32' ? '.cmd' : '')) 6 | 7 | module.exports = { 8 | list: function() { 9 | return spawn(surge, ['list'], { stdio: 'inherit' }) 10 | }, 11 | 12 | publish: function(options) { 13 | return spawn(surge, [options.project, options.domain], { stdio: 'inherit' }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /watcher.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var chokidar = require('chokidar'); 5 | 6 | var log = console.log.bind(console); 7 | 8 | module.exports = function() { 9 | let watcher = chokidar.watch('./**/*', { 10 | persistent: true, 11 | 12 | ignored: './build/**/*', 13 | ignoreInitial: false, 14 | followSymlinks: true, 15 | cwd: '.', 16 | 17 | usePolling: true, 18 | interval: 100, 19 | binaryInterval: 300, 20 | depth: 50, 21 | awaitWriteFinish: { 22 | stabilityThreshold: 1000, 23 | pollInterval: 100 24 | }, 25 | 26 | ignorePermissionErrors: false, 27 | atomic: true 28 | }); 29 | 30 | 31 | // Stop watching. 32 | process.on('SIGINT', () => { 33 | console.log(''); 34 | console.log('Shutting down resurge'); 35 | watcher.close(); 36 | process.exit(0); 37 | }); 38 | 39 | return watcher; 40 | } 41 | --------------------------------------------------------------------------------