diff --git a/packages/cycle-scripts-one-fits-all/LICENSE b/packages/cycle-scripts-one-fits-all/LICENSE new file mode 100644 index 0000000..cb17116 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2017 Nick Balestra + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/cycle-scripts-one-fits-all/README.md b/packages/cycle-scripts-one-fits-all/README.md new file mode 100644 index 0000000..2a4b9b8 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/README.md @@ -0,0 +1,42 @@ +# cycle-scripts + +[Cycle-app](https://github.com/cyclejs-community/create-cycle-app) core flavor. + +## Language + +ES6 ( Babel ) configured with: +* [ES2015 preset](https://babeljs.io/docs/plugins/preset-es2015/) + +## Bundler + +Webpack configured with +* [Webpack dev server](https://webpack.github.io/docs/webpack-dev-server.html) +* [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement-with-webpack.html) + +## Scripts + +- `npm start`: Start development server listening on port 8000 +- `npm test`: Run the default test tool +- `npm run build`: Generate a production-ready build content, on the `build` folder (this folder is *gitignored*) +- `npm run eject`: Copy flavor's dependencies and configurations to the project folder, update `package.json` and remove the dependency on the flavored `cycle-scripts`. This is irreversible. + + +## Boilerplate: + +The flavor generate the following file structure: + +``` +my-awesome-cycle-app/ +├── node_modules/ +├── public/ +│ ├── favicon.ico +│ └── index.html +├── src/ +│ ├── app.js +│ ├── app.test.js +│ └── index.js +└── package.json +``` + +### Config files +* .babelrc (Added on the root after running the eject script) diff --git a/packages/cycle-scripts-one-fits-all/index.js b/packages/cycle-scripts-one-fits-all/index.js new file mode 100644 index 0000000..c019af6 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/index.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node +'use strict' + +const spawn = require('cross-spawn') +const script = process.argv[2] +const args = process.argv.slice(3) + +switch (script) { + case 'start': + case 'test': + case 'build': + case 'eject': + const result = spawn.sync( + 'node', + [require.resolve('./scripts/' + script)].concat(args), + {stdio: 'inherit'} + ) + process.exit(result.status) + break + default: + console.log('Unknown script "' + script + '".') + console.log('Perhaps you need to upgrade cycle-scripts?') + break +} diff --git a/packages/cycle-scripts-one-fits-all/package.json b/packages/cycle-scripts-one-fits-all/package.json new file mode 100644 index 0000000..4815b26 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/package.json @@ -0,0 +1,42 @@ +{ + "name": "cycle-scripts-one-fits-all", + "version": "1.0.0", + "description": "create-cycle-one-fits-all flavor", + "main": "index.js", + "scripts": { + "test": "echo \"Maybe later\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cyclejs-community/create-cycle-app-flavors.git" + }, + "author": "Jan van Brügge ", + "license": "MIT", + "bugs": { + "url": "https://github.com/cyclejs-community/create-cycle-app-flavors/issues" + }, + "homepage": "https://github.com/cyclejs-community/create-cycle-app-flavors#readme", + "bin": { + "cycle-scripts": "./index.js" + }, + "dependencies": { + "@cycle/xstream-run": "^4.2.0", + "@webpack-blocks/babel6": "^0.4.0", + "@webpack-blocks/dev-server2": "^0.4.0", + "@webpack-blocks/extract-text2": "^0.4.0", + "@webpack-blocks/postcss": "^0.4.0", + "@webpack-blocks/sass": "^0.4.0", + "@webpack-blocks/tslint": "^0.4.0", + "@webpack-blocks/typescript": "^0.4.0", + "@webpack-blocks/webpack2": "^0.4.0", + "autoprefixer": "^6.7.2", + "babel-plugin-transform-react-jsx": "^6.22.0", + "babel-preset-es2015-native-modules": "^6.9.4", + "copy-webpack-plugin": "^4.0.1", + "html-webpack-plugin": "^2.28.0", + "progress-bar-webpack-plugin": "^1.9.3", + "typescript": "^2.1.5", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.3.0" + } +} diff --git a/packages/cycle-scripts-one-fits-all/scripts/build.js b/packages/cycle-scripts-one-fits-all/scripts/build.js new file mode 100644 index 0000000..bb51668 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/build.js @@ -0,0 +1,13 @@ +'use strict' + +const webpack = require('webpack') + +const config = require('./configs/webpack.config.js'); + +const compiler = webpack(config); + +compiler.run((err, stats) => { + if (err) { + console.log(err) + } +}) diff --git a/packages/cycle-scripts-one-fits-all/scripts/configs/.babelrc b/packages/cycle-scripts-one-fits-all/scripts/configs/.babelrc new file mode 100644 index 0000000..f59bcc2 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/configs/.babelrc @@ -0,0 +1,9 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "syntax-jsx", + ["transform-react-jsx", {"pragma": "snabb.html"}] + ] +} diff --git a/packages/cycle-scripts-one-fits-all/scripts/configs/webpack.config.js b/packages/cycle-scripts-one-fits-all/scripts/configs/webpack.config.js new file mode 100644 index 0000000..9a9085f --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/configs/webpack.config.js @@ -0,0 +1,56 @@ +const { createConfig, defineConstants, env, entryPoint, setOutput, sourceMaps, addPlugins } = require('@webpack-blocks/webpack2'); +const babel = require('@webpack-blocks/babel6'); +const devServer = require('@webpack-blocks/dev-server2'); +const postcss = require('@webpack-blocks/postcss'); +const sass = require('@webpack-blocks/sass'); +const typescript = require('@webpack-blocks/typescript'); +const tslint = require('@webpack-blocks/tslint'); +const extractText = require('@webpack-blocks/extract-text2'); +const autoprefixer = require('autoprefixer'); +const webpack = require('webpack'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ProgressBarPlugin = require('progress-bar-webpack-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = createConfig([ + entryPoint('./src/index.ts'), + entryPoint('./src/styles.scss'), + setOutput('./build/bundle.js'), + babel(), + typescript(), + tslint(), + sass(), + extractText('[name].css', 'text/x-sass'), + extractText('[name].css', 'text/css'), + postcss([ + autoprefixer({ browsers: ['last 2 versions'] }) + ]), + defineConstants({ + 'process.env.NODE_ENV': process.env.NODE_ENV + }), + addPlugins([ + new HtmlWebpackPlugin({ + template: './index.ejs', + inject: true, + favicon: 'favicon.png', + hash: true + }), + new webpack.ProvidePlugin({ + snabb: 'snabbdom-jsx' + }), + new ProgressBarPlugin() + ]), + env('development', [ + devServer(), + devServer.proxy({ + '/api': { target: 'http://localhost:3000' } + }), + sourceMaps() + ]), + env('production', [ + addPlugins([ + new webpack.optimize.UglifyJsPlugin(), + new CopyWebpackPlugin([{ from: 'public', to: 'build' }]) + ]) + ]) +]) diff --git a/packages/cycle-scripts-one-fits-all/scripts/eject.js b/packages/cycle-scripts-one-fits-all/scripts/eject.js new file mode 100644 index 0000000..83fd47b --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/eject.js @@ -0,0 +1,50 @@ +'use strict' + +const fs = require('fs-extra') +const path = require('path') +const mkdirp = require('mkdirp') + +const ownPackageJsonPath = path.resolve(__dirname, '..', 'package.json') +const appPackageJsonPath = path.join(process.cwd(), 'package.json') +const ownPackageJson = JSON.parse(fs.readFileSync(ownPackageJsonPath)) +const appPackageJson = JSON.parse(fs.readFileSync(appPackageJsonPath)) +const scriptsPath = path.join(process.cwd(), '.scripts') + +// Declaring new scripts +const scripts = { + start: 'NODE_ENV=development webpack --config webpack.config.js', + test: 'mocha --colors --require babel-register src/**/**.test.js', + build: 'NODE_ENV=production webpack --config webpack.config.js' +} + +// Declare the new dependencies, excluding self +let devDependencies = {} +Object.keys(appPackageJson.devDependencies) + .filter(dep => dep !== ownPackageJson.name) + .filter(dep => dependencies.indexOf(dep) === -1) + .forEach(dep => { + devDependencies[dep] = appPackageJson.devDependencies[dep] + }) +devDependencies = Object.assign({}, devDependencies, ownPackageJson.dependencies) + +// Delete babel config in package.json +delete appPackageJson.babel + +// Write the new package.json +const newPackageJson = Object.assign({}, appPackageJson, {scripts: scripts, devDependencies: devDependencies}) +fs.writeFileSync( + appPackageJsonPath, + JSON.stringify(newPackageJson, null, 2) +) + +mkdirp(scriptsPath, () => { + function copy (script, subDir, inRoot) { + subDir = subDir || '' + fs.copySync(path.join(__dirname, subDir, script), path.join(inRoot ? '' : scriptsPath, script)) + } + + // Copy configs + copy('.babelrc', 'configs', true) + copy('webpack.config.js', 'configs', true) +}) + diff --git a/packages/cycle-scripts-one-fits-all/scripts/init.js b/packages/cycle-scripts-one-fits-all/scripts/init.js new file mode 100644 index 0000000..6fe99f9 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/init.js @@ -0,0 +1,118 @@ +'use strict' + +const fs = require('fs-extra') +const path = require('path') +const chalk = require('chalk') +const spawn = require('cross-spawn') + +const basicDependencies = [ + '@cycle/dom', + '@cycle/http', + '@cycle/xstream-run', + 'xstream' +] + +function patchGitignore (appPath) { + // Rename gitignore after the fact to prevent npm from renaming it to .npmignore + // See: https://github.com/npm/npm/issues/1862 + const gitignorePath = path.join(appPath, 'gitignore') + const dotGitignorePath = path.join(appPath, '.gitignore') + fs.move(gitignorePath, dotGitignorePath, [], (err) => { + if (err) { + // Append if there's already a `.gitignore` file there + if (err.code === 'EEXIST') { + const content = fs.readFileSync(gitignorePath) + fs.appendFileSync(dotGitignorePath, content) + fs.unlinkSync(gitignorePath) + } else { + throw err + } + } + }) +} + +function successMsg (appName, appPath) { + console.log() + console.log(`Success! Created ${appName} at ${appPath}`) + console.log('Inside that directory, you can run several commands:') + console.log() + console.log(chalk.cyan(' npm start')) + console.log(' Starts the development server') + console.log() + console.log(chalk.cyan(' npm test')) + console.log(' Start the test runner') + console.log() + console.log(chalk.cyan(' npm run build')) + console.log(' Bundles the app into static files for production') + console.log() + console.log(chalk.cyan(' npm run eject')) + console.log(' Removes this tool and copies build dependencies, configuration files') + console.log(' and scripts into the app directory. If you do this, you can\'t go back!') + console.log() + console.log('We suggest that you begin by typing:') + console.log() + console.log(chalk.cyan(` cd ${appName}`)) + console.log(chalk.cyan(' npm start')) + console.log() + console.log('If you have questions, issues or feedback about Cycle.js and create-cycle-app, please, join us on the Gitter:') + console.log() + console.log(chalk.cyan(' https://gitter.im/cyclejs/cyclejs')) + console.log() + console.log('Happy cycling!') + console.log() +} + +module.exports = function init (appPath, appName, verbose, originalDirectory) { + const ownPackageName = require(path.join(__dirname, '..', 'package.json')).name + const ownPath = path.join(appPath, 'node_modules', ownPackageName) + const appPackageJson = path.join(appPath, 'package.json') + const appPackage = require(appPackageJson) + + // Manipulate app's package.json + appPackage.dependencies = appPackage.dependencies || {} + appPackage.devDependencies = appPackage.devDependencies || {} + appPackage.scripts = { + 'start': 'cycle-scripts start', + 'test': 'cycle-scripts test', + 'build': 'cycle-scripts build', + 'eject': 'cycle-scripts eject' + } + // TODO: move into own babel config file + appPackage.babel = { + 'presets': ['es2015'] + } + fs.writeFileSync( + appPackageJson, + JSON.stringify(appPackage, null, 2) + ) + + // Copy flavor files + fs.copySync(path.join(ownPath, 'template'), appPath) + patchGitignore(appPath) + + const listOfbasicDependencies = basicDependencies + .slice(0, (basicDependencies.length - 1)) + .join(', ') + .concat(` and ${basicDependencies.slice(-1)}`) + + console.log(`Installing ${listOfbasicDependencies} using npm...`) + console.log() + + const args = [ + 'install' + ].concat( + basicDependencies + ).concat([ + '--save', + verbose && '--verbose' + ]).filter(Boolean) + + var proc = spawn('npm', args, {stdio: 'inherit'}) + proc.on('close', function (code) { + if (code !== 0) { + console.error(chalk.red('`npm ' + args.join(' ') + '` failed')) + return + } + successMsg(appName, appPath) + }) +} diff --git a/packages/cycle-scripts-one-fits-all/scripts/start.js b/packages/cycle-scripts-one-fits-all/scripts/start.js new file mode 100644 index 0000000..9dd3d1c --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/start.js @@ -0,0 +1,13 @@ +'use strict' + +const webpack = require('webpack') +const WebpackDevServer = require('webpack-dev-server') + +const port = 8080 + +const config = require('./configs/webpack.config.js') + +const compiler = webpack(config) +const server = new WebpackDevServer(compiler) + +server.listen(port) diff --git a/packages/cycle-scripts-one-fits-all/scripts/test.js b/packages/cycle-scripts-one-fits-all/scripts/test.js new file mode 100644 index 0000000..13d2b6c --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/scripts/test.js @@ -0,0 +1,17 @@ +'use strict' + +const path = require('path') +const spawn = require('cross-spawn') +const chalk = require('chalk') + +const mocha = path.resolve(process.cwd(), 'node_modules', '.bin', 'mocha') + +const args = [ + '--colors', + '--require', + 'babel-register', + !process.env.CI && (console.log(chalk.green.bold('Enabling watch mode')) || '--watch'), + 'src/**/*.test.js' +].filter(Boolean) + +spawn(mocha, args, {stdio: 'inherit'}) diff --git a/packages/cycle-scripts-one-fits-all/template/gitignore b/packages/cycle-scripts-one-fits-all/template/gitignore new file mode 100644 index 0000000..1f2f649 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/template/gitignore @@ -0,0 +1,3 @@ +build/ + +*.log diff --git a/packages/cycle-scripts-one-fits-all/template/public/favicon.ico b/packages/cycle-scripts-one-fits-all/template/public/favicon.ico new file mode 100644 index 0000000..9750148 Binary files /dev/null and b/packages/cycle-scripts-one-fits-all/template/public/favicon.ico differ diff --git a/packages/cycle-scripts-one-fits-all/template/src/app.test.ts b/packages/cycle-scripts-one-fits-all/template/src/app.test.ts new file mode 100644 index 0000000..599e959 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/template/src/app.test.ts @@ -0,0 +1,7 @@ +// import assert from 'assert' + +// describe('App', function () { +// it('should test something', function () { +// // TODO: Add your tests here +// }) +// }) diff --git a/packages/cycle-scripts-one-fits-all/template/src/app.tsx b/packages/cycle-scripts-one-fits-all/template/src/app.tsx new file mode 100644 index 0000000..38666c8 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/template/src/app.tsx @@ -0,0 +1,15 @@ +import xs, { Stream } from 'xstream'; +import { VNode } from '@cycle/dom'; + +import { Sources, Sinks } from './interfaces'; + +export function App(sources : Sources) : Sinks +{ + const vdom$ : Stream = xs.of( +
My Awesome Cycle.js app
+ ); + + return { + DOM: vdom$ + }; +} diff --git a/packages/cycle-scripts-one-fits-all/template/src/index.ts b/packages/cycle-scripts-one-fits-all/template/src/index.ts new file mode 100644 index 0000000..01a59f0 --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/template/src/index.ts @@ -0,0 +1,13 @@ +import { run } from '@cycle/xstream-run'; +import { makeDOMDriver } from '@cycle/dom'; +import { makeHTTPDriver } from '@cycle/http'; +import { App } from './app' + +const main = App; + +const drivers : any = { + DOM: makeDOMDriver('#app'), + HTTP: makeHTTPDriver() +} + +run(main, drivers); diff --git a/packages/cycle-scripts-one-fits-all/template/src/interfaces.ts b/packages/cycle-scripts-one-fits-all/template/src/interfaces.ts new file mode 100644 index 0000000..1b5caba --- /dev/null +++ b/packages/cycle-scripts-one-fits-all/template/src/interfaces.ts @@ -0,0 +1,16 @@ +import { Stream } from 'xstream'; +import { VNode } from '@cycle/dom'; +import { DOMSource } from '@cycle/dom/xstream-typings'; +import { HTTPSource, RequestOptions } from '@cycle/http'; + +export interface Sources +{ + DOM : DOMSource; + HTTP : HTTPSource; +} + +export interface Sinks +{ + DOM : Stream; + HTTP : Stream; +}