diff --git a/package.json b/package.json index 4ba15f02..dd044c0b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": false, "scripts": { "lint": "yarn lint:js && yarn lint:css", - "lint:js": "eslint src test", + "lint:js": "eslint src test scripts", "lint:js:fix": "yarn lint:js --fix", "lint:css": "stylelint src/**/*.scss", "lint:css:fix": "yarn lint:css --fix", diff --git a/scripts/build.js b/scripts/build.js index f9fc02b5..f6db9d86 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,4 +1,4 @@ -'use strict'; +/* eslint no-console: "off" */ // Do this as the first thing so that any code reading it knows the right env. process.env.BABEL_ENV = 'production'; @@ -7,7 +7,7 @@ process.env.NODE_ENV = 'production'; // Makes the script crash on unhandled rejections instead of silently // ignoring them. In the future, promise rejections that are not handled will // terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { +process.on('unhandledRejection', (err) => { throw err; }); @@ -18,38 +18,38 @@ const path = require('path'); const chalk = require('chalk'); const fs = require('fs-extra'); const webpack = require('webpack'); -const config = require('../config/webpack.config.prod'); -const paths = require('../config/paths'); const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); const printBuildError = require('react-dev-utils/printBuildError'); const AdmZip = require('adm-zip'); +const paths = require('../config/paths'); +const config = require('../config/webpack.config.prod'); -const measureFileSizesBeforeBuild = - FileSizeReporter.measureFileSizesBeforeBuild; -const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; +const { measureFileSizesBeforeBuild, printFileSizesAfterBuild } = FileSizeReporter; const useYarn = fs.existsSync(paths.yarnLockFile); // These sizes are pretty large. We'll warn for bundles exceeding them. -const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; -const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; +const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; // eslint-disable-line +const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; // eslint-disable-line // Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { +if (!checkRequiredFiles([ paths.appHtml, paths.appIndexJs ])) { process.exit(1); } // First, read the current file sizes in build directory. // This lets us display how much they changed later. measureFileSizesBeforeBuild(paths.appBuild) - .then(previousFileSizes => { + .then((previousFileSizes) => { // Remove all content but keep the directory so that // if you're in it, you don't end up in Trash fs.emptyDirSync(paths.appBuild); + // Merge with the public folder copyPublicFolder(); + // Start the webpack build return build(previousFileSizes); }) @@ -59,14 +59,14 @@ measureFileSizesBeforeBuild(paths.appBuild) console.log(chalk.yellow('Compiled with warnings.\n')); console.log(warnings.join('\n\n')); console.log( - '\nSearch for the ' + - chalk.underline(chalk.yellow('keywords')) + - ' to learn more about each warning.' + `\nSearch for the ${ + chalk.underline(chalk.yellow('keywords')) + } to learn more about each warning.` ); console.log( - 'To ignore, add ' + - chalk.cyan('// eslint-disable-next-line') + - ' to the line before.\n' + `To ignore, add ${ + chalk.cyan('// eslint-disable-next-line') + } to the line before.\n` ); } else { console.log(chalk.green('Compiled successfully.\n')); @@ -83,9 +83,11 @@ measureFileSizesBeforeBuild(paths.appBuild) console.log(); const appPackage = require(paths.appPackageJson); - const publicUrl = paths.publicUrl; - const publicPath = config.output.publicPath; + + const { publicUrl } = paths; + const { publicPath } = config.output; const buildFolder = path.relative(process.cwd(), paths.appBuild); + printHostingInstructions( appPackage, publicUrl, @@ -94,7 +96,7 @@ measureFileSizesBeforeBuild(paths.appBuild) useYarn ); }, - err => { + (err) => { console.log(chalk.red('Failed to compile.\n')); printBuildError(err); process.exit(1); @@ -106,19 +108,23 @@ measureFileSizesBeforeBuild(paths.appBuild) function build(previousFileSizes) { console.log('Creating an optimized production build...'); - let compiler = webpack(config); + const compiler = webpack(config); + return new Promise((resolve, reject) => { compiler.run((err, stats) => { if (err) { return reject(err); } + const messages = formatWebpackMessages(stats.toJson({}, true)); + if (messages.errors.length) { // Only keep the first error. Others are often indicative // of the same problem, but confuse the reader with noise. if (messages.errors.length > 1) { messages.errors.length = 1; } + return reject(new Error(messages.errors.join('\n\n'))); } if ( @@ -133,8 +139,10 @@ function build(previousFileSizes) { 'Most CI servers set it automatically.\n' ) ); + return reject(new Error(messages.warnings.join('\n\n'))); } + return resolve({ stats, previousFileSizes, @@ -147,17 +155,19 @@ function build(previousFileSizes) { function copyPublicFolder() { fs.copySync(paths.appPublic, paths.appBuild, { dereference: true, - filter: file => file !== paths.appHtml, + filter: (file) => file !== paths.appHtml, }); } function zipDist() { + const minArgsToContainVersion = 3; + // If no version was provided, do nothing - if (process.argv.length < 3) { + if (process.argv.length < minArgsToContainVersion) { return; } - const version = process.argv[2]; + const [ , , version ] = process.argv; const versionFileName = `./dist/shlink-web-client_${version}_dist.zip`; console.log(chalk.cyan(`Generating dist file for version ${chalk.bold(version)}...`)); @@ -167,6 +177,7 @@ function zipDist() { if (fs.existsSync(versionFileName)) { fs.unlink(versionFileName); } + zip.addLocalFolder('./build', `shlink-web-client_${version}_dist`); zip.writeZip(versionFileName); console.log(chalk.green('Dist file properly generated')); diff --git a/scripts/start.js b/scripts/start.js index c5acbe57..9332e4e9 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -1,4 +1,4 @@ -'use strict'; +/* eslint no-console: "off" */ // Do this as the first thing so that any code reading it knows the right env. process.env.BABEL_ENV = 'development'; @@ -7,7 +7,7 @@ process.env.NODE_ENV = 'development'; // Makes the script crash on unhandled rejections instead of silently // ignoring them. In the future, promise rejections that are not handled will // terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { +process.on('unhandledRejection', (err) => { throw err; }); @@ -35,12 +35,13 @@ const useYarn = fs.existsSync(paths.yarnLockFile); const isInteractive = process.stdout.isTTY; // Warn and crash if required files are missing -if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { +if (!checkRequiredFiles([ paths.appHtml, paths.appIndexJs ])) { process.exit(1); } // Tools like Cloud9 rely on this. -const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; +const FALLBACK_PORT = 3000; +const DEFAULT_PORT = parseInt(process.env.PORT, 10) || FALLBACK_PORT; const HOST = process.env.HOST || '0.0.0.0'; if (process.env.HOST) { @@ -52,7 +53,7 @@ if (process.env.HOST) { ) ); console.log( - `If this was unintentional, check that you haven't mistakenly set it in your shell.` + 'If this was unintentional, check that you haven\'t mistakenly set it in your shell.' ); console.log(`Learn more here: ${chalk.yellow('http://bit.ly/2mwWSwH')}`); console.log(); @@ -61,47 +62,59 @@ if (process.env.HOST) { // We attempt to use the default port but if it is busy, we offer the user to // run on a different port. `choosePort()` Promise resolves to the next free port. choosePort(HOST, DEFAULT_PORT) - .then(port => { - if (port == null) { + .then((port) => { + if (port === null) { // We have not found a port. return; } + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const appName = require(paths.appPackageJson).name; + const urls = prepareUrls(protocol, HOST, port); + // Create a webpack compiler that is configured with custom messages. const compiler = createCompiler(webpack, config, appName, urls, useYarn); + // Load proxy config const proxySetting = require(paths.appPackageJson).proxy; + const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + // Serve webpack assets generated by the compiler over a web sever. const serverConfig = createDevServerConfig( proxyConfig, urls.lanUrlForConfig ); const devServer = new WebpackDevServer(compiler, serverConfig); + // Launch WebpackDevServer. - devServer.listen(port, HOST, err => { + + devServer.listen(port, HOST, (err) => { if (err) { - return console.log(err); + console.log(err); + + return; } if (isInteractive) { clearConsole(); } + console.log(chalk.cyan('Starting the development server...\n')); openBrowser(urls.localUrlForBrowser); }); - ['SIGINT', 'SIGTERM'].forEach(function(sig) { - process.on(sig, function() { + [ 'SIGINT', 'SIGTERM' ].forEach((sig) => { + process.on(sig, () => { devServer.close(); process.exit(); }); }); }) - .catch(err => { + .catch((err) => { if (err && err.message) { console.log(err.message); } + process.exit(1); }); diff --git a/scripts/test.js b/scripts/test.js index c8a26746..c5f8efe9 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -1,4 +1,3 @@ -'use strict'; // Do this as the first thing so that any code reading it knows the right env. process.env.BABEL_ENV = 'test'; @@ -8,7 +7,7 @@ process.env.PUBLIC_URL = ''; // Makes the script crash on unhandled rejections instead of silently // ignoring them. In the future, promise rejections that are not handled will // terminate the Node.js process with a non-zero exit code. -process.on('unhandledRejection', err => { +process.on('unhandledRejection', (err) => { throw err; }); @@ -17,6 +16,8 @@ require('../config/env'); // Make tests to be matched inside tests folder const jest = require('jest'); -let argv = process.argv.slice(2); + +const argumentsToRemove = 2; +const argv = process.argv.slice(argumentsToRemove); jest.run(argv);