ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

commit a2404103c2dc2144821c28e24cc2d7be51a79a9d
parent e73083eb1d50a4035bf5d11803a822fbdd41289b
Author: Vladimir Kutepov <frenzzy.man@gmail.com>
Date:   Mon, 27 Feb 2017 13:32:03 +0300

Improve deploy script (#1150)


Diffstat:
M.gitignore | 2--
Mpublic/humans.txt | 8++++----
Mtools/README.md | 13+++++++------
Mtools/clean.js | 8+-------
Mtools/deploy.js | 34+++++++++++++++++++++++++++-------
Mtools/lib/cp.js | 13++++++++++++-
Mtools/lib/fs.js | 20++++++++++++++++++++
Mtools/webpack.config.js | 57+++++++--------------------------------------------------
8 files changed, 78 insertions(+), 77 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -6,5 +6,3 @@ database.sqlite node_modules ncp-debug.log npm-debug.log -stats.json -report.html diff --git a/public/humans.txt b/public/humans.txt @@ -3,13 +3,13 @@ # TEAM - <name> -- <role> -- <twitter> + <name> -- <role> -- <twitter> # THANKS - <name> + <name> # TECHNOLOGY COLOPHON - CSS3, HTML5, JavaScript - React, Flux, SuperAgent + CSS3, HTML5, JavaScript + React Starter Kit -- https://reactstarter.com/ diff --git a/tools/README.md b/tools/README.md @@ -1,6 +1,6 @@ -## Build Automation Tools +# Build Automation Tools -##### `yarn start` (`start.js`) +### `yarn start` (`start.js`) * Cleans up the output `/build` directory (`clean.js`) * Copies static files to the output folder (`copy.js`) @@ -10,23 +10,24 @@ [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement), and [React Hot Loader](https://github.com/gaearon/react-hot-loader) -##### `yarn run build` (`build.js`) +### `yarn run build` (`build.js`) * Cleans up the output `/build` folder (`clean.js`) * Copies static files to the output folder (`copy.js`) * Creates application bundles with Webpack (`bundle.js`, `webpack.config.js`) -##### `yarn run deploy` (`deploy.js`) +### `yarn run deploy` (`deploy.js`) * Builds the project from source files (`build.js`) * Pushes the contents of the `/build` folder to a remote server with Git -##### Options +## Options Flag | Description ----------- | -------------------------------------------------- `--release` | Minimizes and optimizes the compiled output `--verbose` | Prints detailed information to the console +`--analyze` | Launches [Webpack Bundle Analyzer](https://github.com/th0r/webpack-bundle-analyzer) `--static` | Renders [specified routes](./render.js#L15) as static html files `--docker` | Build an image from a Dockerfile @@ -42,7 +43,7 @@ or $ yarn start -- --release # Launch dev server in production mode ``` -#### Misc +## Misc * `webpack.config.js` - Webpack configuration for both client-side and server-side bundles * `postcss.config.js` - PostCSS configuration for transforming styles with JS plugins diff --git a/tools/clean.js b/tools/clean.js @@ -17,13 +17,7 @@ function clean() { cleanDir('build/*', { nosort: true, dot: true, - ignore: ['build/.git', 'build/public'], - }), - - cleanDir('build/public/*', { - nosort: true, - dot: true, - ignore: ['build/public/.git'], + ignore: ['build/.git'], }), ]); } diff --git a/tools/deploy.js b/tools/deploy.js @@ -10,7 +10,7 @@ import path from 'path'; import fetch from 'node-fetch'; import { spawn } from './lib/cp'; -import { makeDir } from './lib/fs'; +import { makeDir, moveDir, cleanDir } from './lib/fs'; import run from './run'; // GitHub Pages @@ -22,6 +22,14 @@ const remote = { static: true, }; +// Heroku +// const remote = { +// name: 'heroku', +// url: 'https://git.heroku.com/<app>.git', +// branch: 'master', +// website: 'https://<app>.herokuapp.com', +// }; + // Azure Web Apps // const remote = { // name: 'azure', @@ -31,7 +39,7 @@ const remote = { // }; const options = { - cwd: path.resolve(__dirname, '../build', remote.static ? 'public' : ''), + cwd: path.resolve(__dirname, '../build'), stdio: ['ignore', 'inherit', 'inherit'], }; @@ -40,7 +48,7 @@ const options = { */ async function deploy() { // Initialize a new repository - await makeDir('build/public'); + await makeDir('build'); await spawn('git', ['init', '--quiet'], options); // Changing a remote's URL @@ -56,10 +64,10 @@ async function deploy() { // Fetch the remote repository if it exists let isRefExists = false; try { - await spawn('git', ['ls-remote', '--exit-code', remote.url, remote.branch], options); + await spawn('git', ['ls-remote', '--quiet', '--exit-code', remote.url, remote.branch], options); isRefExists = true; } catch (error) { - /* skip */ + await spawn('git', ['update-ref', '-d', 'HEAD'], options); } if (isRefExists) { await spawn('git', ['fetch', remote.name], options); @@ -72,11 +80,23 @@ async function deploy() { process.argv.push('--release'); if (remote.static) process.argv.push('--static'); await run(require('./build').default); + if (process.argv.includes('--static')) { + await cleanDir('build/*', { + nosort: true, + dot: true, + ignore: ['build/.git', 'build/public'], + }); + await moveDir('build/public', 'build'); + } // Push the contents of the build folder to the remote server via Git await spawn('git', ['add', '.', '--all'], options); - await spawn('git', ['commit', '--message', `Update ${new Date().toISOString()}`], options); - await spawn('git', ['push', remote.name, `master:${remote.branch}`, '--force', '--set-upstream'], options); + try { + await spawn('git', ['diff', '--cached', '--exit-code', '--quiet'], options); + } catch (error) { + await spawn('git', ['commit', '--message', `Update ${new Date().toISOString()}`], options); + } + await spawn('git', ['push', remote.name, `master:${remote.branch}`, '--set-upstream'], options); // Check if the site was successfully deployed const response = await fetch(remote.website); diff --git a/tools/lib/cp.js b/tools/lib/cp.js @@ -19,4 +19,15 @@ export const spawn = (command, args, options) => new Promise((resolve, reject) = }); }); -export default { spawn }; +export const exec = (command, options) => new Promise((resolve, reject) => { + cp.exec(command, options, (err, stdout, stderr) => { + if (err) { + reject(err); + return; + } + + resolve({ stdout, stderr }); + }); +}); + +export default { spawn, exec }; diff --git a/tools/lib/fs.js b/tools/lib/fs.js @@ -21,6 +21,10 @@ export const writeFile = (file, contents) => new Promise((resolve, reject) => { fs.writeFile(file, contents, 'utf8', err => (err ? reject(err) : resolve())); }); +export const renameFile = (source, target) => new Promise((resolve, reject) => { + fs.rename(source, target, err => (err ? reject(err) : resolve())); +}); + export const copyFile = (source, target) => new Promise((resolve, reject) => { let cbCalled = false; function done(err) { @@ -50,6 +54,20 @@ export const makeDir = name => new Promise((resolve, reject) => { mkdirp(name, err => (err ? reject(err) : resolve())); }); +export const moveDir = async (source, target) => { + const dirs = await readDir('**/*.*', { + cwd: source, + nosort: true, + dot: true, + }); + await Promise.all(dirs.map(async (dir) => { + const from = path.resolve(source, dir); + const to = path.resolve(target, dir); + await makeDir(path.dirname(to)); + await renameFile(from, to); + })); +}; + export const copyDir = async (source, target) => { const dirs = await readDir('**/*.*', { cwd: source, @@ -71,9 +89,11 @@ export const cleanDir = (pattern, options) => new Promise((resolve, reject) => export default { readFile, writeFile, + renameFile, copyFile, readDir, makeDir, copyDir, + moveDir, cleanDir, }; diff --git a/tools/webpack.config.js b/tools/webpack.config.js @@ -15,21 +15,7 @@ import pkg from '../package.json'; const isDebug = !process.argv.includes('--release'); const isVerbose = process.argv.includes('--verbose'); -const isAnalyse = process.argv.includes('--analyse') || process.argv.includes('--analyze'); -const port = parseInt(process.env.PORT || '3000', 10); -const analyzerPort = port + 3; - -// Can be `server`, `static` or `disabled`. -// In `server` mode analyzer will start HTTP server to show bundle report. -// In `static` mode single HTML file with bundle report will be generated. -// In `disabled` mode you can use this plugin to just generate Webpack Stats JSON -// file by setting `generateStatsFile` to `true`. -let analyzerMode = 'disabled'; -if (isAnalyse) { - analyzerMode = 'server'; -} else if (!isDebug) { - analyzerMode = 'static'; -} +const isAnalyze = process.argv.includes('--analyze') || process.argv.includes('--analyse'); // // Common configuration chunk to be used for both @@ -37,7 +23,7 @@ if (isAnalyse) { // ----------------------------------------------------------------------------- const config = { - context: path.resolve(__dirname, '../src'), + context: path.resolve(__dirname, '..'), output: { path: path.resolve(__dirname, '../build/public/assets'), @@ -144,10 +130,6 @@ const config = { ], }, - resolve: { - modules: [path.resolve(__dirname, '../src'), 'node_modules'], - }, - // Don't attempt to continue if there are any errors. bail: !isDebug, @@ -177,7 +159,7 @@ const clientConfig = { target: 'web', entry: { - client: ['babel-polyfill', './client.js'], + client: ['babel-polyfill', './src/client.js'], }, output: { @@ -186,8 +168,6 @@ const clientConfig = { chunkFilename: isDebug ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js', }, - resolve: { ...config.resolve }, - plugins: [ // Define free variables // https://webpack.github.io/docs/list-of-plugins.html#defineplugin @@ -233,30 +213,9 @@ const clientConfig = { }), ], - new BundleAnalyzerPlugin({ - // See above - analyzerMode, - // Host that will be used in `server` mode to start HTTP server. - analyzerHost: '127.0.0.1', - // Port that will be used in `server` mode to start HTTP server. - analyzerPort, - // Path to bundle report file that will be generated in `static` mode. - // Relative to bundles output directory. - reportFilename: path.resolve(__dirname, '../report.html'), - // Automatically open report in default browser - openAnalyzer: true, - // If `true`, Webpack Stats JSON file will be generated in bundles output directory - generateStatsFile: !isDebug, - // Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`. - // Relative to bundles output directory. - statsFilename: path.resolve(__dirname, '../stats.json'), - // Options for `stats.toJson()` method. - // You can exclude sources of your modules from stats file with `source: false` option. - // See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21 - statsOptions: null, - // Log level. Can be 'info', 'warn', 'error' or 'silent'. - logLevel: 'info', - }), + // Webpack Bundle Analyzer + // https://github.com/th0r/webpack-bundle-analyzer + ...isAnalyze ? [new BundleAnalyzerPlugin()] : [], ], // Choose a developer tool to enhance debugging @@ -285,7 +244,7 @@ const serverConfig = { target: 'node', entry: { - server: ['babel-polyfill', './server.js'], + server: ['babel-polyfill', './src/server.js'], }, output: { @@ -314,8 +273,6 @@ const serverConfig = { })), }, - resolve: { ...config.resolve }, - externals: [ /^\.\/assets\.json$/, (context, request, callback) => {