From 3329bb66e80c1596d28472ef20722fd78cfddaba Mon Sep 17 00:00:00 2001 From: Lucas Rosa Date: Fri, 5 May 2017 14:31:57 -0400 Subject: [PATCH 01/12] attempt to keep src folder pure elm --- config/paths.js | 6 +++--- template/{src => public}/favicon.ico | Bin template/{src => public}/index.html | 0 template/{src => public}/index.js | 2 +- template/{src => public}/logo.svg | 0 template/{src => public}/main.css | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename template/{src => public}/favicon.ico (100%) rename template/{src => public}/index.html (100%) rename template/{src => public}/index.js (78%) rename template/{src => public}/logo.svg (100%) rename template/{src => public}/main.css (100%) diff --git a/config/paths.js b/config/paths.js index d71a0ab3..3b49fac2 100644 --- a/config/paths.js +++ b/config/paths.js @@ -4,10 +4,10 @@ const appRoot = process.cwd() let paths = { appRoot, - entry: path.resolve('./src/index.js'), + entry: path.resolve('./public/index.js'), dist: path.resolve('./dist'), - template: path.resolve('./src/index.html'), - favicon: path.resolve('./src/favicon.ico'), + template: path.resolve('./public/index.html'), + favicon: path.resolve('./public/favicon.ico'), elmPkg: path.resolve('elm-package.json'), elmMake: require('elm/platform').executablePaths['elm-make'], servedPath: './' || process.env.SERVED_PATH diff --git a/template/src/favicon.ico b/template/public/favicon.ico similarity index 100% rename from template/src/favicon.ico rename to template/public/favicon.ico diff --git a/template/src/index.html b/template/public/index.html similarity index 100% rename from template/src/index.html rename to template/public/index.html diff --git a/template/src/index.js b/template/public/index.js similarity index 78% rename from template/src/index.js rename to template/public/index.js index e93b8eba..e82355fe 100644 --- a/template/src/index.js +++ b/template/public/index.js @@ -1,6 +1,6 @@ import './main.css' const logoPath = require('./logo.svg') -const Elm = require('./App.elm') +const Elm = require('../src/App.elm') const root = document.getElementById('root') diff --git a/template/src/logo.svg b/template/public/logo.svg similarity index 100% rename from template/src/logo.svg rename to template/public/logo.svg diff --git a/template/src/main.css b/template/public/main.css similarity index 100% rename from template/src/main.css rename to template/public/main.css From b17a1724edb0f88a1648788589b11bafb141cf41 Mon Sep 17 00:00:00 2001 From: Lucas Rosa Date: Sat, 6 May 2017 16:24:36 -0400 Subject: [PATCH 02/12] more structure --- config/paths.js | 2 +- template/public/{ => css}/main.css | 0 template/public/js/index.js | 8 ++++++++ template/public/{ => media}/logo.svg | 0 4 files changed, 9 insertions(+), 1 deletion(-) rename template/public/{ => css}/main.css (100%) create mode 100644 template/public/js/index.js rename template/public/{ => media}/logo.svg (100%) diff --git a/config/paths.js b/config/paths.js index 3b49fac2..f8eb60ef 100644 --- a/config/paths.js +++ b/config/paths.js @@ -4,7 +4,7 @@ const appRoot = process.cwd() let paths = { appRoot, - entry: path.resolve('./public/index.js'), + entry: path.resolve('./public/js/index.js'), dist: path.resolve('./dist'), template: path.resolve('./public/index.html'), favicon: path.resolve('./public/favicon.ico'), diff --git a/template/public/main.css b/template/public/css/main.css similarity index 100% rename from template/public/main.css rename to template/public/css/main.css diff --git a/template/public/js/index.js b/template/public/js/index.js new file mode 100644 index 00000000..8f73776c --- /dev/null +++ b/template/public/js/index.js @@ -0,0 +1,8 @@ +import '../css/main.css'; + +const logoPath = require('../media/logo.svg'); +const Elm = require('../../src/App.elm'); + +const root = document.getElementById('root'); + +Elm.App.embed(root, logoPath) diff --git a/template/public/logo.svg b/template/public/media/logo.svg similarity index 100% rename from template/public/logo.svg rename to template/public/media/logo.svg From 9d2f1d2189641e3951f78c29f4c2811dce3514da Mon Sep 17 00:00:00 2001 From: Lucas Rosa Date: Thu, 1 Jun 2017 10:58:56 -0400 Subject: [PATCH 03/12] extra index.js --- template/public/index.js | 7 ------- template/public/js/index.js | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 template/public/index.js diff --git a/template/public/index.js b/template/public/index.js deleted file mode 100644 index e82355fe..00000000 --- a/template/public/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './main.css' -const logoPath = require('./logo.svg') -const Elm = require('../src/App.elm') - -const root = document.getElementById('root') - -Elm.App.embed(root, logoPath) diff --git a/template/public/js/index.js b/template/public/js/index.js index 8f73776c..c187b5cd 100644 --- a/template/public/js/index.js +++ b/template/public/js/index.js @@ -1,8 +1,8 @@ -import '../css/main.css'; +import '../css/main.css' -const logoPath = require('../media/logo.svg'); -const Elm = require('../../src/App.elm'); +const logoPath = require('../media/logo.svg') +const Elm = require('../../src/App.elm') -const root = document.getElementById('root'); +const root = document.getElementById('root') Elm.App.embed(root, logoPath) From 37ed9711367a964960a69e82896077a11c5fe405 Mon Sep 17 00:00:00 2001 From: Eduard Kyvenko Date: Sun, 11 Jun 2017 22:08:49 +0200 Subject: [PATCH 04/12] style: Remove standard --- config/env.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/config/env.js b/config/env.js index 6827ce27..5ff71dbd 100644 --- a/config/env.js +++ b/config/env.js @@ -1,10 +1,8 @@ -function getClientEnvironment () { - return Object - .keys(process.env) - .reduce((acc, current) => { - acc[ `process.env.${current}` ] = `"${process.env[ current ]}"` - return acc - }, {}) +function getClientEnvironment() { + return Object.keys(process.env).reduce((acc, current) => { + acc[`process.env.${current}`] = `"${process.env[current]}"`; + return acc; + }, {}); } -module.exports = getClientEnvironment +module.exports = getClientEnvironment; From 0360af29a866c0b5ad9f77c0629954d084114b78 Mon Sep 17 00:00:00 2001 From: Eduard Kyvenko Date: Sun, 11 Jun 2017 22:10:26 +0200 Subject: [PATCH 05/12] feat: Fix the paths and introduce the new build script --- bin/create-elm-app-cli.js | 34 +++--- bin/elm-app-cli.js | 89 ++++++++------- config/paths.js | 27 +++-- config/webpack.config.dev.js | 33 +++--- config/webpack.config.prod.js | 44 ++++---- config/webpackDevServer.config.js | 44 +++++--- scripts/build.js | 140 +++++++++++++++++++----- scripts/create.js | 121 +++++++++++---------- scripts/eject.js | 166 ++++++++++++++-------------- scripts/start.js | 173 +++++++++++++++--------------- template/public/js/index.js | 10 +- tests/cliAccessibility.js | 62 ++++++----- tests/create-elm-app.spec.js | 72 +++++++------ tests/elm-app.build.spec.js | 115 ++++++++++---------- tests/elm-app.dist.spec.js | 60 ++++++----- tests/elm-app.eject.spec.js | 133 ++++++++++++----------- tests/elm-app.test.spec.js | 62 +++++------ 17 files changed, 774 insertions(+), 611 deletions(-) diff --git a/bin/create-elm-app-cli.js b/bin/create-elm-app-cli.js index df976cc1..9c330964 100755 --- a/bin/create-elm-app-cli.js +++ b/bin/create-elm-app-cli.js @@ -1,22 +1,24 @@ #!/usr/bin/env node -const path = require('path') -const spawn = require('cross-spawn') -const argv = require('minimist')(process.argv.slice(2)) -const version = require('../package.json').version -const elmPlatformVersion = require('elm/package.json').version -const commands = argv._ +const path = require('path'); +const spawn = require('cross-spawn'); +const argv = require('minimist')(process.argv.slice(2)); +const version = require('../package.json').version; +const elmPlatformVersion = require('elm/package.json').version; +const commands = argv._; if (commands.length === 0) { - console.log('\nUsage: create-elm-app \n') - console.log('where is the name of the directory with your future project') - console.log('\nElm Platform ' + elmPlatformVersion + '\n') - console.log('create-elm-app@' + version + ' ' + path.resolve(__dirname, '..')) - process.exit(1) + console.log('\nUsage: create-elm-app \n'); + console.log( + 'where is the name of the directory with your future project' + ); + console.log('\nElm Platform ' + elmPlatformVersion + '\n'); + console.log( + 'create-elm-app@' + version + ' ' + path.resolve(__dirname, '..') + ); + process.exit(1); } -spawn.sync( - 'node', - [ path.resolve(__dirname, '../scripts/create'), commands ], - { stdio: 'inherit' } -) +spawn.sync('node', [path.resolve(__dirname, '../scripts/create'), commands], { + stdio: 'inherit' +}); diff --git a/bin/elm-app-cli.js b/bin/elm-app-cli.js index 7f890776..f9d653cc 100755 --- a/bin/elm-app-cli.js +++ b/bin/elm-app-cli.js @@ -1,22 +1,22 @@ #!/usr/bin/env node -const path = require('path') -const spawn = require('cross-spawn') -const argv = require('minimist')(process.argv.slice(2)) -const executablePaths = require('elm/platform').executablePaths +const path = require('path'); +const spawn = require('cross-spawn'); +const argv = require('minimist')(process.argv.slice(2)); +const executablePaths = require('elm/platform').executablePaths; const version = require('../package.json').version const elmPlatformVersion = require('elm/package.json').version -const commands = argv._ +const commands = argv._; if (commands.length === 0) { - help(version) - process.exit(1) + help(version); + process.exit(1); } -const script = commands[ 0 ] -const scriptArgs = commands.splice(1) +const script = commands[0]; +const scriptArgs = commands.splice(1); switch (script) { case 'create': @@ -24,44 +24,43 @@ switch (script) { case 'eject': case 'start': spawnSyncNode(path.resolve(__dirname, '../scripts', script), scriptArgs); - break + break; case 'test': { - let args = [] - Object.keys(argv || {}).forEach(function (key) { + let args = []; + Object.keys(argv || {}).forEach(function(key) { if (key !== '_' && key !== 'compiler') { - args = args.concat([ '--' + key, argv[ key ] ]) + args = args.concat(['--' + key, argv[key]]); } - }) + }); - args = args.concat([ '--compiler', path.normalize(executablePaths[ 'elm-make' ]) ]) + args = args.concat([ + '--compiler', + path.normalize(executablePaths['elm-make']) + ]); - const cp = spawn.sync( - require.resolve('elm-test/bin/elm-test'), - args, - { stdio: 'inherit' } - ) + const cp = spawn.sync(require.resolve('elm-test/bin/elm-test'), args, { + stdio: 'inherit' + }); if (cp.status !== 0) { - process.exit(cp.status) + process.exit(cp.status); } - break + break; } default: // Proxy elm-platform cli commands. - if ([ 'package', 'reactor', 'make', 'repl' ].indexOf(script) !== -1) { - const executable = executablePaths[ 'elm-' + script ] + if (['package', 'reactor', 'make', 'repl'].indexOf(script) !== -1) { + const executable = executablePaths['elm-' + script]; - spawn.sync( - path.normalize(executable), - process.argv.slice(3), - { stdio: 'inherit' } - ) - break + spawn.sync(path.normalize(executable), process.argv.slice(3), { + stdio: 'inherit' + }); + break; } else { - help(version) - process.exit(1) + help(version); + process.exit(1); } } @@ -71,12 +70,14 @@ switch (script) { * @param {string} version [description] * @return {undefined} */ -function help (version) { - console.log('\nUsage: elm-app \n') - console.log('where is one of:') - console.log(' create, build, start, package, reactor, make, repl\n') - console.log('\nElm ' + elmPlatformVersion + '\n') - console.log('create-elm-app@' + version + ' ' + path.resolve(__dirname, '..')) +function help(version) { + console.log('\nUsage: elm-app \n'); + console.log('where is one of:'); + console.log(' create, build, start, package, reactor, make, repl\n'); + console.log('\nElm ' + elmPlatformVersion + '\n'); + console.log( + 'create-elm-app@' + version + ' ' + path.resolve(__dirname, '..') + ); } /** @@ -86,14 +87,12 @@ function help (version) { * @param {Arrays} args Script arguments * @return {undefined} */ -function spawnSyncNode (script, args) { - const cp = spawn.sync( - 'node', - [ script ].concat(args || []), - { stdio: 'inherit' } - ) +function spawnSyncNode(script, args) { + const cp = spawn.sync('node', [script].concat(args || []), { + stdio: 'inherit' + }); if (cp.status !== 0) { - process.exit(cp.status) + process.exit(cp.status); } } diff --git a/config/paths.js b/config/paths.js index f8eb60ef..9c36663f 100644 --- a/config/paths.js +++ b/config/paths.js @@ -1,16 +1,23 @@ -const path = require('path') +const path = require('path'); +const fs = require('fs'); -const appRoot = process.cwd() +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebookincubator/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = relativePath => path.resolve(appDirectory, relativePath); let paths = { - appRoot, - entry: path.resolve('./public/js/index.js'), - dist: path.resolve('./dist'), - template: path.resolve('./public/index.html'), - favicon: path.resolve('./public/favicon.ico'), - elmPkg: path.resolve('elm-package.json'), + appPath: resolveApp('.'), + appPublic: resolveApp('./public'), + appHtml: resolveApp('./public/index.html'), + appIndexJs: resolveApp('./src/index.js'), + appSrc: resolveApp('./src'), + entry: resolveApp('./src/index.js'), + appBuild: resolveApp('./build'), + elmPkg: resolveApp('./elm-package.json'), + scripts: path.resolve(__dirname, '../scripts'), elmMake: require('elm/platform').executablePaths['elm-make'], servedPath: './' || process.env.SERVED_PATH -} +}; -module.exports = paths +module.exports = paths; diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 8bfc18ac..8c510f17 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -1,19 +1,19 @@ -const autoprefixer = require('autoprefixer') -const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin') -const DefinePlugin = require('webpack/lib/DefinePlugin') -const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin') -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin') -const HtmlWebpackPlugin = require('html-webpack-plugin') -const getClientEnvironment = require('./env') -const configPaths = require('../config/paths') +const autoprefixer = require('autoprefixer'); +const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin'); +const DefinePlugin = require('webpack/lib/DefinePlugin'); +const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin'); +const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const getClientEnvironment = require('./env'); +const configPaths = require('../config/paths'); // Webpack uses `publicPath` to determine where the app is being served from. // In development, we always serve from the root. This makes config easier. -const publicPath = '/' +const publicPath = '/'; // `publicUrl` is just like `publicPath`, but we will provide it to our app // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. -const publicUrl = '' +const publicUrl = ''; module.exports = { devtool: 'eval', @@ -25,14 +25,14 @@ module.exports = { // Replacement runtime. require.resolve('webpack/hot/dev-server'), - configPaths.entry + paths.appIndexJs ], output: { pathinfo: true, // The build folder. - path: configPaths.dist, + path: paths.appBuild, // Generated JS files. filename: 'dist/js/bundle.js', @@ -49,7 +49,6 @@ module.exports = { noParse: /\.elm$/, rules: [ - { test: /\.js$/, exclude: [/elm-stuff/, /node_modules/], @@ -76,7 +75,7 @@ module.exports = { verbose: true, warn: true, debug: true, - pathToMake: configPaths.elmMake, + pathToMake: paths.elmMake, forceWatch: true } } @@ -137,15 +136,13 @@ module.exports = { new InterpolateHtmlPlugin({ PUBLIC_URL: publicUrl }), - new HtmlWebpackPlugin({ inject: true, - template: configPaths.template, - favicon: configPaths.favicon + template: paths.appHtml }), new HotModuleReplacementPlugin(), new NamedModulesPlugin() ] -} +}; diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 2652ea8b..f9801654 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -1,30 +1,33 @@ -const autoprefixer = require('autoprefixer') -const DefinePlugin = require('webpack/lib/DefinePlugin') -const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin') -const HtmlWebpackPlugin = require('html-webpack-plugin') -const ExtractTextPlugin = require('extract-text-webpack-plugin') -const CleanWebpackPlugin = require('clean-webpack-plugin') -const AssetsPlugin = require('assets-webpack-plugin') -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin') -const getClientEnvironment = require('./env') -const configPaths = require('../config/paths') +const autoprefixer = require('autoprefixer'); +const DefinePlugin = require('webpack/lib/DefinePlugin'); +const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const CleanWebpackPlugin = require('clean-webpack-plugin'); +const AssetsPlugin = require('assets-webpack-plugin'); +const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); +const getClientEnvironment = require('./env'); +const configPaths = require('../config/paths'); // Webpack uses `publicPath` to determine where the app is being served from. // It requires a trailing slash, or the file assets will get an incorrect path. -const publicPath = configPaths.servedPath +const publicPath = paths.servedPath; +// Some apps do not use client-side routing with pushState. +// For these, "homepage" can be set to "." to enable relative asset paths. +const shouldUseRelativeAssetPaths = publicPath === './'; // `publicUrl` is just like `publicPath`, but we will provide it to our app // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. -const publicUrl = publicPath.slice(0, -1) +const publicUrl = publicPath.slice(0, -1); module.exports = { bail: true, - entry: [configPaths.entry], + entry: [paths.appIndexJs], output: { // The build folder. - path: configPaths.dist, + path: paths.appBuild, // Append leading slash when production assets are referenced in the html. publicPath: publicPath, @@ -42,7 +45,6 @@ module.exports = { noParse: /\.elm$/, rules: [ - { test: /\.js$/, exclude: [/elm-stuff/, /node_modules/], @@ -63,7 +65,7 @@ module.exports = { // Use the local installation of elm-make loader: require.resolve('elm-webpack-loader'), options: { - pathToMake: configPaths.elmMake + pathToMake: paths.elmMake } }, @@ -118,18 +120,17 @@ module.exports = { }, plugins: [ - new InterpolateHtmlPlugin({ PUBLIC_URL: publicUrl }), - new AssetsPlugin({path: configPaths.dist}), + new AssetsPlugin({ path: paths.appBuild }), new DefinePlugin(getClientEnvironment()), // Remove the content of the ./dist/ folder. new CleanWebpackPlugin(['dist'], { - root: configPaths.appRoot, + root: paths.appPath, verbose: false, dry: false }), @@ -146,8 +147,7 @@ module.exports = { new HtmlWebpackPlugin({ inject: true, - template: configPaths.template, - favicon: configPaths.favicon, + template: paths.appHtml, minify: { removeComments: true, collapseWhitespace: true, @@ -164,4 +164,4 @@ module.exports = { new ExtractTextPlugin('css/[name].[contenthash:8].css') ] -} +}; diff --git a/config/webpackDevServer.config.js b/config/webpackDevServer.config.js index f79cbed2..3a181c67 100644 --- a/config/webpackDevServer.config.js +++ b/config/webpackDevServer.config.js @@ -1,11 +1,12 @@ -const errorOverlayMiddleware = require('react-error-overlay/middleware') -const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware') -const config = require('./webpack.config.dev') +const errorOverlayMiddleware = require('react-error-overlay/middleware'); +const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); +const config = require('./webpack.config.dev'); +const paths = require('./paths'); -const protocol = process.env.HTTPS === 'true' ? 'https' : 'http' -const host = process.env.HOST || '0.0.0.0' +const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; +const host = process.env.HOST || '0.0.0.0'; -module.exports = function (proxy, allowedHost) { +module.exports = function(proxy, allowedHost) { return { // WebpackDevServer 2.4.3 introduced a security fix that prevents remote // websites from potentially accessing local content through DNS rebinding: @@ -23,13 +24,30 @@ module.exports = function (proxy, allowedHost) { // So we will disable the host check normally, but enable it if you have // specified the `proxy` setting. Finally, we let you override it if you // really know what you're doing with a special environment variable. - disableHostCheck: !proxy || - process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', + disableHostCheck: + !proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', // Enable gzip compression of generated files. compress: true, // Silence WebpackDevServer's own logs since they're generally not useful. // It will still show compile warnings and errors with this setting. clientLogLevel: 'none', + // By default WebpackDevServer serves physical files from current directory + // in addition to all the virtual build products that it serves from memory. + // This is confusing because those files won’t automatically be available in + // production build folder unless we copy them. However, copying the whole + // project directory is dangerous because we may expose sensitive files. + // Instead, we establish a convention that only files in `public` directory + // get served. Our build script will copy `public` into the `build` folder. + // In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%: + // + // In JavaScript code, you can access it with `process.env.PUBLIC_URL`. + // Note that we only recommend to use `public` folder as an escape hatch + // for files like `favicon.ico`, `manifest.json`, and libraries that are + // for some reason broken when imported through Webpack. If you just want to + // use an image, put it in `src` and `import` it from JavaScript instead. + contentBase: paths.appPublic, + // By default files from `contentBase` will not trigger a page reload. + watchContentBase: true, // Enable hot reloading server. It will provide /sockjs-node/ endpoint // for the WebpackDevServer client so it can learn when the files were // updated. The WebpackDevServer client is included as an entry point @@ -58,15 +76,15 @@ module.exports = function (proxy, allowedHost) { }, public: allowedHost, proxy, - setup (app) { + setup(app) { // This lets us open files from the runtime error overlay. - app.use(errorOverlayMiddleware()) + app.use(errorOverlayMiddleware()); // This service worker file is effectively a 'no-op' that will reset any // previous service worker registered for the same host:port combination. // We do this in development to avoid hitting the production cache if // it used the same host and port. // https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432 - app.use(noopServiceWorkerMiddleware()) + app.use(noopServiceWorkerMiddleware()); } - } -} + }; +}; diff --git a/scripts/build.js b/scripts/build.js index 918f121e..e73dbacc 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,35 +1,119 @@ // Load environment variables from .env file. // Suppress warnings if this file is missing. -require('dotenv').config({silent: true}) +require('dotenv').config({ silent: true }); -const fs = require('fs') -const chalk = require('chalk') -const webpack = require('webpack') -const config = require('../config/webpack.config.prod') +const fs = require('fs-extra'); +const chalk = require('chalk'); +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 FileSizeReporter = require('react-dev-utils/FileSizeReporter'); + +const measureFileSizesBeforeBuild = + FileSizeReporter.measureFileSizesBeforeBuild; +const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; if (fs.existsSync('elm-package.json') === false) { - console.log('Please, run the build script from project root directory') - process.exit(1) + console.log('Please, run the build script from project root directory'); + process.exit(1); +} + +// Warn and crash if required files are missing +if (!checkRequiredFiles([paths.appIndexJs, paths.appHtml])) { + 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 => { + // 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); + }) + .then( + ({ stats, previousFileSizes, warnings }) => { + if (warnings.length) { + 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.' + ); + console.log( + 'To ignore, add ' + + chalk.cyan('// eslint-disable-next-line') + + ' to the line before.\n' + ); + } else { + console.log(chalk.green('Compiled successfully.\n')); + } + + console.log('File sizes after gzip:\n'); + printFileSizesAfterBuild(stats, previousFileSizes, paths.appBuild); + console.log(); + + // const appPackage = require(paths.appPackageJson) + // const publicUrl = paths.publicUrl + // const publicPath = config.output.publicPath + // const buildFolder = path.relative(process.cwd(), paths.appBuild) + // printHostingInstructions( + // appPackage, + // publicUrl, + // publicPath, + // buildFolder, + // useYarn + // ) + }, + err => { + console.log(chalk.red('Failed to compile.\n')); + console.log((err.message || err) + '\n'); + process.exit(1); + } + ); + +// Create the production build and print the deployment instructions. +function build(previousFileSizes) { + console.log('Creating an optimized production build...'); + + let 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) { + return reject(new Error(messages.errors.join('\n\n'))); + } + if (process.env.CI && messages.warnings.length) { + console.log( + chalk.yellow( + '\nTreating warnings as errors because process.env.CI = true.\n' + + 'Most CI servers set it automatically.\n' + ) + ); + return reject(new Error(messages.warnings.join('\n\n'))); + } + return resolve({ + stats, + previousFileSizes, + warnings: messages.warnings + }); + }); + }); } -console.log('\nStarting production build...\n') - -// Initialize webpack, using the long way: http://webpack.github.io/docs/node.js-api.html#the-long-way -webpack(config).run((err, stats) => { // eslint-disable-line handle-callback-err - if (stats.compilation.errors.length > 0) { - console.log(stats.toString({ - chunks: false, - colors: true, - assets: false - })) - process.exit(1) - } else { - const statsFormatted = stats.toString({ - chunks: false, - colors: true - }) - - console.log(statsFormatted) - console.log(chalk.green('\n' + 'Production build is ready in `dist/` folder')) - } -}) +function copyPublicFolder() { + fs.copySync(paths.appPublic, paths.appBuild, { + dereference: true, + filter: file => file !== paths.appHtml + }); +} diff --git a/scripts/create.js b/scripts/create.js index e63cc1d6..e0e3b161 100644 --- a/scripts/create.js +++ b/scripts/create.js @@ -1,73 +1,86 @@ -const fs = require('fs') -const copySync = require('fs-extra').copySync -const path = require('path') -const chalk = require('chalk') -const spawnSync = require('child_process').spawnSync -const argv = require('minimist')(process.argv.slice(2)) -const commands = argv._ -const executablePaths = require('elm/platform').executablePaths +const fs = require('fs'); +const copySync = require('fs-extra').copySync; +const path = require('path'); +const chalk = require('chalk'); +const spawnSync = require('child_process').spawnSync; +const argv = require('minimist')(process.argv.slice(2)); +const commands = argv._; +const executablePaths = require('elm/platform').executablePaths; -if (commands.length === 0 || commands[ 0 ] === '') { - console.error( - '\nUsage: elm-app create ' - ) - process.exit(1) +if (commands.length === 0 || commands[0] === '') { + console.error('\nUsage: elm-app create '); + process.exit(1); } -createElmApp(commands[ 0 ]) +createElmApp(commands[0]); -function createElmApp (name) { - console.log('\nCreating ' + name + ' project...\n') +function createElmApp(name) { + console.log('\nCreating ' + name + ' project...\n'); - const root = path.resolve(name) - const template = path.join(__dirname, '../template') + const root = path.resolve(name); + const template = path.join(__dirname, '../template'); if (!fs.existsSync(name)) { try { - copySync(template, root) - fs.renameSync(path.resolve(root, 'gitignore'), path.resolve(root, '.gitignore')) + copySync(template, root); + fs.renameSync( + path.resolve(root, 'gitignore'), + path.resolve(root, '.gitignore') + ); } catch (err) { - console.log(err) - process.exit(1) + console.log(err); + process.exit(1); } } else { - console.log('The directory ' + name + ' already exists. Aborting.') - process.exit(1) + console.log('The directory ' + name + ' already exists. Aborting.'); + process.exit(1); } - process.chdir(root) + process.chdir(root); // Run initial `elm-package install -y` - const spawnElmPkgResult = spawnSync(executablePaths[ 'elm-package' ], [ 'install', '-y' ], { stdio: 'inherit' }) + const spawnElmPkgResult = spawnSync( + executablePaths['elm-package'], + ['install', '-y'], + { stdio: 'inherit' } + ); - if (spawnElmPkgResult.status === null) { - console.log(chalk.red('\nFailed to install elm packages')) - console.log('\nPlease, make sure you have internet connection!') - console.log('\nIn case if you are running Unix OS, you might look in to this issue:') - console.log('\n https://github.com/halfzebra/create-elm-app/issues/10') - process.exit(1) + if (spawnElmPkgResult.status !== 0) { + console.log(chalk.red('\nFailed to install elm packages')); + console.log('\nPlease, make sure you have internet connection!'); + console.log( + '\nIn case if you are running Unix OS, you might look in to this issue:' + ); + console.log('\n https://github.com/halfzebra/create-elm-app/issues/10'); + process.exit(1); } - console.log(chalk.green('\nProject is successfully created in `' + root + '`.')) - console.log() - console.log('Inside that directory, you can run several commands:') - console.log() - console.log(chalk.cyan(' elm-app start')) - console.log(' Starts the development server.') - console.log() - console.log(chalk.cyan(' elm-app build')) - console.log(' Bundles the app into static files for production.') - console.log() - console.log(chalk.cyan(' elm-app test')) - console.log(' Starts the test runner.') - console.log() - console.log(chalk.cyan(' elm-app 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'), name) - console.log(' ' + chalk.cyan('elm-app start')) - console.log() + console.log( + chalk.green('\nProject is successfully created in `' + root + '`.') + ); + console.log(); + console.log('Inside that directory, you can run several commands:'); + console.log(); + console.log(chalk.cyan(' elm-app start')); + console.log(' Starts the development server.'); + console.log(); + console.log(chalk.cyan(' elm-app build')); + console.log(' Bundles the app into static files for production.'); + console.log(); + console.log(chalk.cyan(' elm-app test')); + console.log(' Starts the test runner.'); + console.log(); + console.log(chalk.cyan(' elm-app 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'), name); + console.log(' ' + chalk.cyan('elm-app start')); + console.log(); } diff --git a/scripts/eject.js b/scripts/eject.js index e905d23f..1acda9c8 100644 --- a/scripts/eject.js +++ b/scripts/eject.js @@ -1,103 +1,98 @@ -const path = require('path') -const spawn = require('cross-spawn') -const chalk = require('chalk') -const prompt = require('prompt') -const fs = require('fs-extra') -const Table = require('cli-table') -const pkgOwn = require(path.join(__dirname, '../package.json')) - -function extendOmittingProps (deps, deleteProps) { +const path = require('path'); +const spawn = require('cross-spawn'); +const chalk = require('chalk'); +const prompt = require('prompt'); +const fs = require('fs-extra'); +const Table = require('cli-table'); +const pkgOwn = require(path.join(__dirname, '../package.json')); + +function extendOmittingProps(deps, deleteProps) { if (typeof deleteProps === 'undefined') { - deleteProps = [] + deleteProps = []; } - deps = Object.assign({}, deps) + deps = Object.assign({}, deps); - deleteProps.forEach(function (name) { - delete deps[name] - }) + deleteProps.forEach(function(name) { + delete deps[name]; + }); - return deps + return deps; } -function diffTable (target, mixin, head) { +function diffTable(target, mixin, head) { if (typeof head === 'undefined') { - head = [chalk.grey('Name'), chalk.yellow('Old'), chalk.green('New')] + head = [chalk.grey('Name'), chalk.yellow('Old'), chalk.green('New')]; } const table = new Table({ head: head - }) + }); for (const propName in target) { if (propName in mixin) { - const targetPropValue = target[propName] - const mixinPropValue = mixin[propName] + const targetPropValue = target[propName]; + const mixinPropValue = mixin[propName]; // If found and is not equal if (targetPropValue !== mixinPropValue) { - table.push([propName, targetPropValue, mixinPropValue]) + table.push([propName, targetPropValue, mixinPropValue]); } } } - return table + return table; } -function promptYesOrNo () { +function promptYesOrNo() { return new Promise((resolve, reject) => { const property = { name: 'answer', message: chalk.yellow('Would you like to continue? [Y/n]') - } + }; - prompt.start() - prompt.message = '' + prompt.start(); + prompt.message = ''; - prompt.get(property, (err, result) => { // eslint-disable-line handle-callback-err + prompt.get(property, (err, result) => { + // eslint-disable-line handle-callback-err if (result.answer.search(/^y(es)?$/i) !== -1) { - resolve() + resolve(); } else { - reject('\nAborting...') // eslint-disable-line prefer-promise-reject-errors + reject('\nAborting...'); // eslint-disable-line prefer-promise-reject-errors } - }) - }) + }); + }); } -function performEject (pkg) { +function performEject(pkg) { // Copy the configuration and start/build scripts. try { - fs.copySync(path.resolve(__dirname, 'build.js'), './scripts/build.js') - fs.copySync(path.resolve(__dirname, 'start.js'), './scripts/start.js') - fs.copySync(path.resolve(__dirname, '../config'), './config') + fs.copySync(path.resolve(__dirname, 'build.js'), './scripts/build.js'); + fs.copySync(path.resolve(__dirname, 'start.js'), './scripts/start.js'); + fs.copySync(path.resolve(__dirname, '../config'), './config'); } catch (err) { - console.log(chalk.red('Failed to copy scripts, the error is:\n')) - console.log(err) - process.exit(1) + console.log(chalk.red('Failed to copy scripts, the error is:\n')); + console.log(err); + process.exit(1); } // Update or create new package.json - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)) + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)); - console.log('\nPlease wait for npm to install all required dependencies...') + console.log('\nPlease wait for npm to install all required dependencies...'); // Install npm packages - spawn.sync( - 'npm', - ['install'], - {stdio: 'inherit'} - ) + spawn.sync('npm', ['install'], { stdio: 'inherit' }); - console.log(chalk.green('\nEjected successfully!')) + console.log(chalk.green('\nEjected successfully!')); } // The following dependencies will be removed: -const unusedDependencies = [ - 'cross-spawn', - 'fs-extra', - 'cli-table', - 'prompt' -] -const devDependencies = extendOmittingProps(pkgOwn.dependencies, unusedDependencies) +const unusedDependencies = ['cross-spawn', 'fs-extra', 'cli-table', 'prompt']; +const devDependencies = extendOmittingProps( + pkgOwn.dependencies, + unusedDependencies +); const scripts = { build: 'node scripts/build.js', start: 'node scripts/start.js', @@ -106,54 +101,67 @@ const scripts = { repl: 'elm-repl', reactor: 'elm-reactor', test: 'elm-test' -} +}; if (fs.existsSync('elm-package.json') === false) { - console.log('Please, run the eject script from project root directory') - process.exit(1) + console.log('Please, run the eject script from project root directory'); + process.exit(1); } if (fs.existsSync('./package.json') === true) { - console.log('Found existing package.json') - const pkgEjected = JSON.parse(fs.readFileSync('./package.json', {encoding: 'utf-8'})) + console.log('Found existing package.json'); + const pkgEjected = JSON.parse( + fs.readFileSync('./package.json', { encoding: 'utf-8' }) + ); Promise.resolve() - .then(function () { + .then(function() { if (pkgEjected.hasOwnProperty('devDependencies')) { - const diff = diffTable(pkgEjected.devDependencies, devDependencies) + const diff = diffTable(pkgEjected.devDependencies, devDependencies); if (diff.length !== 0) { - console.log(diff.toString()) - console.log('Ejecting wil overwrite your "devDependencies" in package.json\n') - return promptYesOrNo() + console.log(diff.toString()); + console.log( + 'Ejecting wil overwrite your "devDependencies" in package.json\n' + ); + return promptYesOrNo(); } } }) - .then(function () { - if (pkgEjected.hasOwnProperty('scripts') && Object.keys(pkgEjected.scripts).length === 0) { - const diff = diffTable(pkgEjected.scripts, scripts) + .then(function() { + if ( + pkgEjected.hasOwnProperty('scripts') && + Object.keys(pkgEjected.scripts).length === 0 + ) { + const diff = diffTable(pkgEjected.scripts, scripts); if (diff.length !== 0) { - console.log(diff.toString()) - console.log('Ejecting will overwrite your "scripts" in package.json\n') - return promptYesOrNo() + console.log(diff.toString()); + console.log( + 'Ejecting will overwrite your "scripts" in package.json\n' + ); + return promptYesOrNo(); } } }) - .then(function () { - pkgEjected.devDependencies = Object.assign({}, devDependencies, pkgEjected.devDependencies) - pkgEjected.scripts = Object.assign({}, scripts, pkgEjected.scripts) - performEject(pkgEjected) - }) - .catch(function (error) { - console.log(error) - process.exit(1) + .then(function() { + pkgEjected.devDependencies = Object.assign( + {}, + devDependencies, + pkgEjected.devDependencies + ); + pkgEjected.scripts = Object.assign({}, scripts, pkgEjected.scripts); + performEject(pkgEjected); }) + .catch(function(error) { + console.log(error); + process.exit(1); + }); } else { - console.log(chalk.green('New package.json is created for your project')) + console.log(chalk.green('New package.json is created for your project')); performEject({ name: path.basename(process.cwd()), version: '0.0.1', private: true, scripts: scripts, devDependencies: devDependencies - }) + }); } diff --git a/scripts/start.js b/scripts/start.js index 8994d0c7..92db4b16 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -1,64 +1,67 @@ // Load environment variables from .env file. // Suppress warnings if this file is missing. -require('dotenv').config({silent: true}) - -const fs = require('fs') -const path = require('path') -const chalk = require('chalk') -const webpack = require('webpack') -const WebpackDevServer = require('webpack-dev-server') -const config = require('../config/webpack.config.dev') -const {choosePort, prepareUrls, prepareProxy} = require('react-dev-utils/WebpackDevServerUtils') -const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages') -const clearConsole = require('react-dev-utils/clearConsole') -const openBrowser = require('react-dev-utils/openBrowser') -const createDevServerConfig = require('../config/webpackDevServer.config') -const paths = require('../config/paths') +require('dotenv').config({ silent: true }); + +const fs = require('fs'); +const path = require('path'); +const chalk = require('chalk'); +const webpack = require('webpack'); +const WebpackDevServer = require('webpack-dev-server'); +const config = require('../config/webpack.config.dev'); +const { + choosePort, + prepareUrls, + prepareProxy +} = require('react-dev-utils/WebpackDevServerUtils'); +const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); +const clearConsole = require('react-dev-utils/clearConsole'); +const openBrowser = require('react-dev-utils/openBrowser'); +const createDevServerConfig = require('../config/webpackDevServer.config'); +const paths = require('../config/paths'); if (fs.existsSync('elm-package.json') === false) { - console.log('Please, run the build script from project root directory') - process.exit(0) + console.log('Please, run the build script from project root directory'); + process.exit(0); } -const isInteractive = process.stdout.isTTY +const isInteractive = process.stdout.isTTY; -function printInstructions (appName, urls) { - console.log() - console.log(`You can now view ${chalk.bold(appName)} in the browser.`) - console.log() +function printInstructions(appName, urls) { + console.log(); + console.log(`You can now view ${chalk.bold(appName)} in the browser.`); + console.log(); if (urls.lanUrlForTerminal) { console.log( ` ${chalk.bold('Local:')} ${urls.localUrlForTerminal}` - ) + ); console.log( ` ${chalk.bold('On Your Network:')} ${urls.lanUrlForTerminal}` - ) + ); } else { - console.log(` ${urls.localUrlForTerminal}`) + console.log(` ${urls.localUrlForTerminal}`); } - console.log() - console.log('Note that the development build is not optimized.') + console.log(); + console.log('Note that the development build is not optimized.'); console.log( - `To create a production build, use ` + - `${chalk.cyan('elm-app build')}.` - ) - console.log() + `To create a production build, use ` + `${chalk.cyan('elm-app build')}.` + ); + console.log(); } -function createCompiler (webpack, config, appName, urls) { +function createCompiler(webpack, config, appName, urls) { // "Compiler" is a low-level interface to Webpack. // It lets us listen to some events and provide our own custom messages. - let compiler + let compiler; try { - compiler = webpack(config) + compiler = webpack(config); } catch (err) { - console.log(chalk.red('Failed to compile.')) - console.log() - console.log(err.message || err) - console.log() - process.exit(1) + console.log(chalk.red('Failed to compile.')); + console.log(); + console.log(err.message || err); + console.log(); + process.exit(1); } // "invalid" event fires when you have changed a file, and Webpack is @@ -67,64 +70,64 @@ function createCompiler (webpack, config, appName, urls) { // "invalid" is short for "bundle invalidated", it doesn't imply any errors. compiler.plugin('invalid', () => { if (isInteractive) { - clearConsole() + clearConsole(); } - console.log('Compiling...') - }) + console.log('Compiling...'); + }); - let isFirstCompile = true + let isFirstCompile = true; // "done" event fires when Webpack has finished recompiling the bundle. // Whether or not you have warnings or errors, you will get this event. compiler.plugin('done', stats => { if (isInteractive) { - clearConsole() + clearConsole(); } // We have switched off the default Webpack output in WebpackDevServer // options so we are going to "massage" the warnings and errors and present // them in a readable focused way. - const messages = formatWebpackMessages(stats.toJson({}, true)) - const isSuccessful = !messages.errors.length && !messages.warnings.length + const messages = formatWebpackMessages(stats.toJson({}, true)); + const isSuccessful = !messages.errors.length && !messages.warnings.length; if (isSuccessful) { - console.log(chalk.green('Compiled successfully!')) + console.log(chalk.green('Compiled successfully!')); } if (isSuccessful && (isInteractive || isFirstCompile)) { - printInstructions(appName, urls) + printInstructions(appName, urls); } - isFirstCompile = false + isFirstCompile = false; // If errors exist, only show errors. if (messages.errors.length) { - console.log(chalk.red('Failed to compile.\n')) - console.log(messages.errors.join('\n\n')) - return + console.log(chalk.red('Failed to compile.\n')); + console.log(messages.errors.join('\n\n')); + return; } // Show warnings if no errors were found. if (messages.warnings.length) { - console.log(chalk.yellow('Compiled with warnings.\n')) - console.log(messages.warnings.join('\n\n')) + console.log(chalk.yellow('Compiled with warnings.\n')); + console.log(messages.warnings.join('\n\n')); // Teach some ESLint tricks. console.log( '\nSearch for the ' + - chalk.underline(chalk.yellow('keywords')) + - ' to learn more about each warning.' - ) + 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' - ) + chalk.cyan('// eslint-disable-next-line') + + ' to the line before.\n' + ); } - }) - return compiler + }); + return compiler; } // Tools like Cloud9 rely on this. -const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000 -const HOST = process.env.HOST || '0.0.0.0' +const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; +const HOST = process.env.HOST || '0.0.0.0'; // We attempt to use the default port but if it is busy, we offer the user to // run on a different port. `detect()` Promise resolves to the next free port. @@ -132,44 +135,44 @@ choosePort(HOST, DEFAULT_PORT) .then(port => { if (port == null) { // We have not found a port. - return + return; } - const protocol = process.env.HTTPS === 'true' ? 'https' : 'http' - const appName = path.basename(path.dirname(paths.elmPkg)) - const urls = prepareUrls(protocol, HOST, port) + const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; + const appName = path.basename(path.dirname(paths.elmPkg)); + const urls = prepareUrls(protocol, HOST, port); // Create a webpack compiler that is configured with custom messages. - const compiler = createCompiler(webpack, config, appName, urls) + const compiler = createCompiler(webpack, config, appName, urls); // Load proxy config - const proxySetting = require(paths.elmPkg).proxy - const proxyConfig = prepareProxy(proxySetting, '/') + const proxySetting = require(paths.elmPkg).proxy; + const proxyConfig = prepareProxy(proxySetting, '/'); // Serve webpack assets generated by the compiler over a web sever. const serverConfig = createDevServerConfig( proxyConfig, urls.lanUrlForConfig - ) - const devServer = new WebpackDevServer(compiler, serverConfig) + ); + const devServer = new WebpackDevServer(compiler, serverConfig); // Launch WebpackDevServer. devServer.listen(port, HOST, err => { if (err) { - return console.log(err) + return console.log(err); } if (isInteractive) { - clearConsole() + clearConsole(); } - console.log(chalk.cyan('Starting the development server...\n')) - openBrowser(urls.localUrlForBrowser) + console.log(chalk.cyan('Starting the development server...\n')); + openBrowser(urls.localUrlForBrowser); }); - ['SIGINT', 'SIGTERM'].forEach(function (sig) { - process.on(sig, function () { - devServer.close() - process.exit() - }) - }) + ['SIGINT', 'SIGTERM'].forEach(function(sig) { + process.on(sig, function() { + devServer.close(); + process.exit(); + }); + }); }) .catch(err => { if (err && err.message) { - console.log(err.message) + console.log(err.message); } - process.exit(1) - }) + process.exit(1); + }); diff --git a/template/public/js/index.js b/template/public/js/index.js index c187b5cd..0fdd303a 100644 --- a/template/public/js/index.js +++ b/template/public/js/index.js @@ -1,8 +1,8 @@ -import '../css/main.css' +import '../css/main.css'; -const logoPath = require('../media/logo.svg') -const Elm = require('../../src/App.elm') +const logoPath = require('../media/logo.svg'); +const Elm = require('../../src/App.elm'); -const root = document.getElementById('root') +const root = document.getElementById('root'); -Elm.App.embed(root, logoPath) +Elm.App.embed(root, logoPath); diff --git a/tests/cliAccessibility.js b/tests/cliAccessibility.js index c353bf34..7476c8ce 100644 --- a/tests/cliAccessibility.js +++ b/tests/cliAccessibility.js @@ -1,37 +1,41 @@ /* eslint-env mocha */ -const expect = require('chai').expect -const spawn = require('cross-spawn') -const rimraf = require('rimraf') +const expect = require('chai').expect; +const spawn = require('cross-spawn'); +const rimraf = require('rimraf'); -const testAppName = 'test-app' +const testAppName = 'test-app'; -describe('Test command line interface functionality', function () { - after(function () { - rimraf.sync(testAppName) - }) +describe('Test command line interface functionality', function() { + after(function() { + rimraf.sync(testAppName); + }); - describe('CLI accessibility', function () { - it('`create-elm-app` command should be available', function () { - const output = spawn.sync('create-elm-app').output - expect(output.toString()).to.have.string('Usage: create-elm-app ') - }) + describe('CLI accessibility', function() { + it('`create-elm-app` command should be available', function() { + const output = spawn.sync('create-elm-app').output; + expect(output.toString()).to.have.string( + 'Usage: create-elm-app ' + ); + }); - it('`elm-app` command should be available', function () { - const result = spawn.sync('elm-app') - const output = result.output - expect(output.toString()).to.have.string('Usage: elm-app ') - }) + it('`elm-app` command should be available', function() { + const result = spawn.sync('elm-app'); + const output = result.output; + expect(output.toString()).to.have.string('Usage: elm-app '); + }); - it('`elm-app package` command should be available', function () { - const result = spawn.sync('elm-app', [ 'package' ]) - const output = concatsStringBuffers(result.output) - expect(output).to.have.string('install and publish elm packages') - }) - }) -}) + it('`elm-app package` command should be available', function() { + const result = spawn.sync('elm-app', ['package']); + const output = concatsStringBuffers(result.output); + expect(output).to.have.string('install and publish elm packages'); + }); + }); +}); -function concatsStringBuffers (buffers) { - return buffers.map(function (out) { - return (out !== null) ? out.toString() : '' - }).join('') +function concatsStringBuffers(buffers) { + return buffers + .map(function(out) { + return out !== null ? out.toString() : ''; + }) + .join(''); } diff --git a/tests/create-elm-app.spec.js b/tests/create-elm-app.spec.js index b8df5d9c..ce1ce2db 100644 --- a/tests/create-elm-app.spec.js +++ b/tests/create-elm-app.spec.js @@ -1,38 +1,48 @@ /* eslint-env mocha */ -const path = require('path') -const expect = require('chai').expect -const spawn = require('cross-spawn') -const dircompare = require('dir-compare') -const fs = require('fs') -const rimraf = require('rimraf') +const path = require('path'); +const expect = require('chai').expect; +const spawn = require('cross-spawn'); +const dircompare = require('dir-compare'); +const fs = require('fs'); +const rimraf = require('rimraf'); -const testAppName = 'test-app' -const rootDir = path.resolve(__dirname, '..') -const testAppDir = path.join(rootDir, testAppName) -const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js') +const testAppName = 'test-app'; +const rootDir = path.resolve(__dirname, '..'); +const testAppDir = path.join(rootDir, testAppName); +const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js'); -describe('Create Elm application with `create-elm-app` command', function () { - after(function () { - rimraf.sync(testAppDir) - }) +describe('Create Elm application with `create-elm-app` command', function() { + after(function() { + rimraf.sync(testAppDir); + }); - it('`create-elm-app ' + testAppName + '` should succeed', function () { - const status = spawn.sync('node', [ createElmAppCmd, testAppName ]).status - expect(status).to.be.equal(0) - }).timeout(60 * 1000) + it('`create-elm-app ' + testAppName + '` should succeed', function() { + const status = spawn.sync('node', [createElmAppCmd, testAppName]).status; + expect(status).to.be.equal(0); + }).timeout(60 * 1000); - it('`' + testAppName + '` should have elm-package.json file', function () { - expect(fs.existsSync(path.join(testAppDir, 'elm-package.json'))).to.be.equal(true) - }) + it('`' + testAppName + '` should have elm-package.json file', function() { + expect( + fs.existsSync(path.join(testAppDir, 'elm-package.json')) + ).to.be.equal(true); + }); - it('`' + testAppName + '` should have .gitignore file', function () { - expect(fs.existsSync(path.join(testAppDir, '.gitignore'))).to.be.equal(true) - }) + it('`' + testAppName + '` should have .gitignore file', function() { + expect(fs.existsSync(path.join(testAppDir, '.gitignore'))).to.be.equal( + true + ); + }); - it('`' + testAppName + '` should have the same file structure as template', function () { - const templateDir = path.join(rootDir, 'template') - const options = { excludeFilter: 'elm-stuff, elm-package.json, gitignore, .gitignore' } - const same = dircompare.compareSync(templateDir, testAppDir, options).same - expect(same).to.be.equal(true) - }) -}) + it( + '`' + testAppName + '` should have the same file structure as template', + function() { + const templateDir = path.join(rootDir, 'template'); + const options = { + excludeFilter: 'elm-stuff, elm-package.json, gitignore, .gitignore' + }; + const same = dircompare.compareSync(templateDir, testAppDir, options) + .same; + expect(same).to.be.equal(true); + } + ); +}); diff --git a/tests/elm-app.build.spec.js b/tests/elm-app.build.spec.js index a8da22d6..41632ddd 100644 --- a/tests/elm-app.build.spec.js +++ b/tests/elm-app.build.spec.js @@ -1,61 +1,66 @@ /* eslint-env mocha */ -const fs = require('fs') -const path = require('path') -const spawn = require('cross-spawn') -const rimraf = require('rimraf') -const expect = require('chai').expect - -const testAppName = 'test-app' -const rootDir = path.resolve(__dirname, '..') -const testAppDir = path.join(rootDir, testAppName) -const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js') -const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js') - -describe('Building Elm application with `elm-app build`', function () { - before(function (done) { - const cmd = spawn.sync('node', [ createElmAppCmd, testAppName ]) +const fs = require('fs'); +const path = require('path'); +const spawn = require('cross-spawn'); +const rimraf = require('rimraf'); +const expect = require('chai').expect; + +const testAppName = 'test-app'; +const rootDir = path.resolve(__dirname, '..'); +const testAppDir = path.join(rootDir, testAppName); +const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js'); +const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js'); + +describe('Building Elm application with `elm-app build`', function() { + before(function(done) { + const cmd = spawn.sync('node', [createElmAppCmd, testAppName]); if (cmd.status === 0) { - process.chdir(testAppDir) - done() + process.chdir(testAppDir); + done(); } else { - done(false) + done(false); } - }) - - after(function () { - process.chdir(rootDir) - rimraf.sync(testAppDir) - }) - - it('`elm-app build` should succeed in `' + testAppName + '`', function () { - const result = spawn.sync('node', [ elmAppCmd, 'build' ]) - const outputString = result.output.map(function (out) { - return (out !== null) ? out.toString() : '' - }).join('') - expect(result.status).to.be.equal(0, 'Incorrect exit status code') - expect(outputString).to.have.string('build is ready in `dist/`') - expect(fs.existsSync(path.join(testAppDir, 'dist'))).to.be.equal(true) - }).timeout(12 * 60 * 1000) - - it('`elm-app build` should exit with non zero status code when build failed', function () { - const normalFile = path.join(testAppDir, 'src/App.elm') - const malformedFile = path.join(rootDir, './tests/data/App.elm') - - copyFileSync(normalFile, 'App.elm-normal') - copyFileSync(malformedFile, normalFile) - - const result = spawn.sync('node', [ elmAppCmd, 'build' ]) - - const oldNormalFile = path.resolve('App.elm-normal') - copyFileSync(oldNormalFile, normalFile) - fs.unlink(oldNormalFile) - - expect(result.status).to.be.at.least(1) - }).timeout(2 * 60 * 1000) -}) - -function copyFileSync (from, to) { - const fromData = fs.readFileSync(from) - fs.writeFileSync(to, fromData) + }); + + after(function() { + process.chdir(rootDir); + rimraf.sync(testAppDir); + }); + + it('`elm-app build` should succeed in `' + testAppName + '`', function() { + const result = spawn.sync('node', [elmAppCmd, 'build']); + const outputString = result.output + .map(function(out) { + return out !== null ? out.toString() : ''; + }) + .join(''); + expect(result.status).to.be.equal(0, 'Incorrect exit status code'); + expect(outputString).to.have.string('build is ready in `dist/`'); + expect(fs.existsSync(path.join(testAppDir, 'dist'))).to.be.equal(true); + }).timeout(12 * 60 * 1000); + + it( + '`elm-app build` should exit with non zero status code when build failed', + function() { + const normalFile = path.join(testAppDir, 'src/App.elm'); + const malformedFile = path.join(rootDir, './tests/data/App.elm'); + + copyFileSync(normalFile, 'App.elm-normal'); + copyFileSync(malformedFile, normalFile); + + const result = spawn.sync('node', [elmAppCmd, 'build']); + + const oldNormalFile = path.resolve('App.elm-normal'); + copyFileSync(oldNormalFile, normalFile); + fs.unlink(oldNormalFile); + + expect(result.status).to.be.at.least(1); + } + ).timeout(2 * 60 * 1000); +}); + +function copyFileSync(from, to) { + const fromData = fs.readFileSync(from); + fs.writeFileSync(to, fromData); } diff --git a/tests/elm-app.dist.spec.js b/tests/elm-app.dist.spec.js index c3674a00..5b0751e6 100644 --- a/tests/elm-app.dist.spec.js +++ b/tests/elm-app.dist.spec.js @@ -1,52 +1,54 @@ /* eslint-disable */ /* eslint-env mocha */ -const fs = require('fs') -const path = require('path') -const spawn = require('cross-spawn') -const rimraf = require('rimraf') -const expect = require('chai').expect -const Nightmare = require('nightmare') +const fs = require('fs'); +const path = require('path'); +const spawn = require('cross-spawn'); +const rimraf = require('rimraf'); +const expect = require('chai').expect; +const Nightmare = require('nightmare'); -const testAppName = 'test-app' -const rootDir = path.resolve(__dirname, '..') -const testAppDir = path.join(rootDir, testAppName) -const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js') -const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js') +const testAppName = 'test-app'; +const rootDir = path.resolve(__dirname, '..'); +const testAppDir = path.join(rootDir, testAppName); +const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js'); +const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js'); -describe('Creating and making a dist build of Elm application', function () { - this.timeout(25000) +describe('Creating and making a dist build of Elm application', function() { + this.timeout(25000); before(done => { spawn('node', [createElmAppCmd, testAppName]).on('close', status => { if (status === 0) { - spawn('node', [elmAppCmd, 'build'], {cwd: testAppDir}).on('close', status => { + spawn('node', [elmAppCmd, 'build'], { + cwd: testAppDir + }).on('close', status => { if (status === 0) { - done() + done(); } - }) + }); } else { - done(false) + done(false); } - }) - }) + }); + }); after(() => { - rimraf.sync(testAppDir) - }) + rimraf.sync(testAppDir); + }); it('compiled correctly and renders "Your Elm App is working!" text', done => { Nightmare() .goto('file://' + path.resolve(testAppDir, 'dist/index.html')) .evaluate(() => { - return document.body.innerText + return document.body.innerText; }) .end() - .then((result) => { - expect(result.trim()).to.be.equal('Your Elm App is working!') - done() + .then(result => { + expect(result.trim()).to.be.equal('Your Elm App is working!'); + done(); }) .catch(err => { - done(err) - }) - }) -}) + done(err); + }); + }); +}); diff --git a/tests/elm-app.eject.spec.js b/tests/elm-app.eject.spec.js index 06777d1a..f04a8cf4 100644 --- a/tests/elm-app.eject.spec.js +++ b/tests/elm-app.eject.spec.js @@ -1,78 +1,87 @@ /* eslint-env mocha */ -const fs = require('fs') -const path = require('path') -const expect = require('chai').expect -const spawn = require('cross-spawn') -const dircompare = require('dir-compare') -const rimraf = require('rimraf') +const fs = require('fs'); +const path = require('path'); +const expect = require('chai').expect; +const spawn = require('cross-spawn'); +const dircompare = require('dir-compare'); +const rimraf = require('rimraf'); -const testAppName = 'test-app' -const rootDir = path.resolve(__dirname, '..') -const testAppDir = path.join(rootDir, testAppName) -const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js') -const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js') +const testAppName = 'test-app'; +const rootDir = path.resolve(__dirname, '..'); +const testAppDir = path.join(rootDir, testAppName); +const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js'); +const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js'); -describe('Ejecting Elm application. (Please wait...)', function () { - before(function (done) { - const cmd = spawn.sync('node', [ createElmAppCmd, testAppName ]) +describe('Ejecting Elm application. (Please wait...)', function() { + before(function(done) { + const cmd = spawn.sync('node', [createElmAppCmd, testAppName]); if (cmd.status === 0) { - process.chdir(testAppDir) - done() + process.chdir(testAppDir); + done(); } else { - done(false) + done(false); } - }) + }); - after(function () { - process.chdir(rootDir) - rimraf.sync(testAppDir) - }) + after(function() { + process.chdir(rootDir); + rimraf.sync(testAppDir); + }); - it('`elm-app eject` should succeed in `' + testAppName + '`', function () { - const result = spawn.sync('node', [ elmAppCmd, 'eject' ]) - const outputString = result.output.map(function (out) { - return (out !== null) ? out.toString() : '' - }).join('') + it('`elm-app eject` should succeed in `' + testAppName + '`', function() { + const result = spawn.sync('node', [elmAppCmd, 'eject']); + const outputString = result.output + .map(function(out) { + return out !== null ? out.toString() : ''; + }) + .join(''); - expect(result.status).to.be.equal(0) - expect(outputString).to.have.string('Ejected successfully!') - }).timeout(10 * 60 * 1000) + expect(result.status).to.be.equal(0); + expect(outputString).to.have.string('Ejected successfully!'); + }).timeout(10 * 60 * 1000); - it('Ejected application should have `package.json` with scripts from Create Elm App', function () { - const testAppPkg = path.join(testAppDir, './package.json') - const pkg = fs.readFileSync(testAppPkg, { encoding: 'utf-8' }) - const pkgScripts = JSON.parse(pkg).scripts + it('Ejected application should have `package.json` with scripts from Create Elm App', function() { + const testAppPkg = path.join(testAppDir, './package.json'); + const pkg = fs.readFileSync(testAppPkg, { encoding: 'utf-8' }); + const pkgScripts = JSON.parse(pkg).scripts; - expect(pkgScripts).to.have.property('build', 'node scripts/build.js') - expect(pkgScripts).to.have.property('start', 'node scripts/start.js') - expect(pkgScripts).to.have.property('package', 'elm-package') - expect(pkgScripts).to.have.property('make', 'elm-make') - expect(pkgScripts).to.have.property('repl', 'elm-repl') - expect(pkgScripts).to.have.property('reactor', 'elm-reactor') - }) + expect(pkgScripts).to.have.property('build', 'node scripts/build.js'); + expect(pkgScripts).to.have.property('start', 'node scripts/start.js'); + expect(pkgScripts).to.have.property('package', 'elm-package'); + expect(pkgScripts).to.have.property('make', 'elm-make'); + expect(pkgScripts).to.have.property('repl', 'elm-repl'); + expect(pkgScripts).to.have.property('reactor', 'elm-reactor'); + }); - it('Ejected application should have build and start scripts', function () { - expect(fs.existsSync(path.join(testAppDir, './scripts/build.js'))) - .to.be.equal(true) - expect(fs.existsSync(path.join(testAppDir, './scripts/start.js'))) - .to.be.equal(true) - }) + it('Ejected application should have build and start scripts', function() { + expect( + fs.existsSync(path.join(testAppDir, './scripts/build.js')) + ).to.be.equal(true); + expect( + fs.existsSync(path.join(testAppDir, './scripts/start.js')) + ).to.be.equal(true); + }); - it('Ejected application should have the config available', function () { - const path1 = path.join(rootDir, './config') - const path2 = path.join(testAppDir, './config') - const same = dircompare.compareSync(path1, path2).same - expect(same).to.be.equal(true) - }) + it('Ejected application should have the config available', function() { + const path1 = path.join(rootDir, './config'); + const path2 = path.join(testAppDir, './config'); + const same = dircompare.compareSync(path1, path2).same; + expect(same).to.be.equal(true); + }); - it('It should be possible to build ejected applitaction, using npm scripts', function () { - const result = spawn.sync('npm', [ 'run', 'build' ]) - const outputString = result.output.map(function (out) { - return (out !== null) ? out.toString() : '' - }).join('') + it( + 'It should be possible to build ejected applitaction, using npm scripts', + function() { + const result = spawn.sync('npm', ['run', 'build']); + const outputString = result.output + .map(function(out) { + return out !== null ? out.toString() : ''; + }) + .join(''); - expect(result.status).to.be.equal(0) - expect(outputString).to.have.string('build is ready in `dist/`') - }).timeout(5 * 60 * 1000) -}) + expect(result.status).to.be.equal(0); + expect(outputString).to.have.string('build is ready in `dist/`'); + } + ).timeout(5 * 60 * 1000); +}); diff --git a/tests/elm-app.test.spec.js b/tests/elm-app.test.spec.js index 46a3a5e9..5dd5c5ed 100644 --- a/tests/elm-app.test.spec.js +++ b/tests/elm-app.test.spec.js @@ -1,40 +1,42 @@ /* eslint-env mocha */ -const path = require('path') -const spawn = require('cross-spawn') -const rimraf = require('rimraf') -const expect = require('chai').expect +const path = require('path'); +const spawn = require('cross-spawn'); +const rimraf = require('rimraf'); +const expect = require('chai').expect; -const testAppName = 'test-app' -const rootDir = path.resolve(__dirname, '..') -const testAppDir = path.join(rootDir, testAppName) -const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js') -const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js') +const testAppName = 'test-app'; +const rootDir = path.resolve(__dirname, '..'); +const testAppDir = path.join(rootDir, testAppName); +const createElmAppCmd = path.join(rootDir, 'bin/create-elm-app-cli.js'); +const elmAppCmd = path.join(rootDir, 'bin/elm-app-cli.js'); -describe('Testing Elm application with `elm-app test` (Please wait...)', function () { - before(function (done) { - const cmd = spawn.sync('node', [ createElmAppCmd, testAppName ]) +describe('Testing Elm application with `elm-app test` (Please wait...)', function() { + before(function(done) { + const cmd = spawn.sync('node', [createElmAppCmd, testAppName]); if (cmd.status === 0) { - process.chdir(testAppDir) - done() + process.chdir(testAppDir); + done(); } else { - done(false) + done(false); } - }) + }); - after(function () { - process.chdir(rootDir) - rimraf.sync(testAppDir) - }) + after(function() { + process.chdir(rootDir); + rimraf.sync(testAppDir); + }); - it('`elm-app test` should succeed in `' + testAppName + '`', function () { - const result = spawn.sync('node', [ elmAppCmd, 'test' ]) - const outputString = result.output.map(function (out) { - return (out !== null) ? out.toString() : '' - }).join('') + it('`elm-app test` should succeed in `' + testAppName + '`', function() { + const result = spawn.sync('node', [elmAppCmd, 'test']); + const outputString = result.output + .map(function(out) { + return out !== null ? out.toString() : ''; + }) + .join(''); - expect(result.status).to.be.at.least(1) - expect(outputString).to.have.string('This test should fail') - expect(outputString).to.have.string('failed as expected!') - }).timeout(2 * 60 * 1000) -}) + expect(result.status).to.be.at.least(1); + expect(outputString).to.have.string('This test should fail'); + expect(outputString).to.have.string('failed as expected!'); + }).timeout(2 * 60 * 1000); +}); From dd315c4068f016222b5582210b7ec44605f2e811 Mon Sep 17 00:00:00 2001 From: Eduard Kyvenko Date: Mon, 12 Jun 2017 19:20:51 +0200 Subject: [PATCH 06/12] chore: Start the ejected package version at 1.0.0 --- scripts/eject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/eject.js b/scripts/eject.js index 1acda9c8..e583449c 100644 --- a/scripts/eject.js +++ b/scripts/eject.js @@ -159,7 +159,7 @@ if (fs.existsSync('./package.json') === true) { console.log(chalk.green('New package.json is created for your project')); performEject({ name: path.basename(process.cwd()), - version: '0.0.1', + version: '1.0.0', private: true, scripts: scripts, devDependencies: devDependencies From 58df0dbd39ed2513cd354656d8b9026011c256fc Mon Sep 17 00:00:00 2001 From: Eduard Kyvenko Date: Tue, 13 Jun 2017 21:20:06 +0200 Subject: [PATCH 07/12] feat(config): Change the name of the distribution folder to `build` BREAKING CHANGE: added `public/` folder and changed the config to serve static assets from it. --- .eslintignore | 2 + .gitignore | 2 +- bin/create-elm-app-cli.js | 2 + bin/elm-app-cli.js | 4 +- config/env.js | 2 + config/paths.js | 38 ++++++++++++++-- config/webpack.config.dev.js | 24 +++++++--- config/webpack.config.prod.js | 85 +++++++++++++++++++++-------------- template/README.md | 4 +- template/gitignore | 2 +- template/public/index.html | 3 +- tests/elm-app.build.spec.js | 4 +- tests/elm-app.dist.spec.js | 4 +- tests/elm-app.eject.spec.js | 2 +- 14 files changed, 122 insertions(+), 56 deletions(-) diff --git a/.eslintignore b/.eslintignore index a72d1b22..e328c937 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ elm-stuff/ +template/ +tests/ diff --git a/.gitignore b/.gitignore index fc6b3c2a..cdc5cd68 100644 --- a/.gitignore +++ b/.gitignore @@ -89,7 +89,7 @@ elm-stuff repl-temp-* # create-elm-app -template/dist +template/build template/package.json # Desktop Services Store on macOS diff --git a/bin/create-elm-app-cli.js b/bin/create-elm-app-cli.js index 9c330964..ed4592c3 100755 --- a/bin/create-elm-app-cli.js +++ b/bin/create-elm-app-cli.js @@ -1,5 +1,7 @@ #!/usr/bin/env node +'use strict'; + const path = require('path'); const spawn = require('cross-spawn'); const argv = require('minimist')(process.argv.slice(2)); diff --git a/bin/elm-app-cli.js b/bin/elm-app-cli.js index f9d653cc..6ed535b2 100755 --- a/bin/elm-app-cli.js +++ b/bin/elm-app-cli.js @@ -1,5 +1,7 @@ #!/usr/bin/env node +'use strict'; + const path = require('path'); const spawn = require('cross-spawn'); const argv = require('minimist')(process.argv.slice(2)); @@ -28,7 +30,7 @@ switch (script) { case 'test': { let args = []; - Object.keys(argv || {}).forEach(function(key) { + Object.keys(argv || {}).forEach(key => { if (key !== '_' && key !== 'compiler') { args = args.concat(['--' + key, argv[key]]); } diff --git a/config/env.js b/config/env.js index 5ff71dbd..83f2be82 100644 --- a/config/env.js +++ b/config/env.js @@ -1,3 +1,5 @@ +'use strict'; + function getClientEnvironment() { return Object.keys(process.env).reduce((acc, current) => { acc[`process.env.${current}`] = `"${process.env[current]}"`; diff --git a/config/paths.js b/config/paths.js index 9c36663f..6ea49c65 100644 --- a/config/paths.js +++ b/config/paths.js @@ -1,12 +1,43 @@ +'use strict'; + const path = require('path'); const fs = require('fs'); +const url = require('url'); // Make sure any symlinks in the project folder are resolved: // https://github.com/facebookincubator/create-react-app/issues/637 const appDirectory = fs.realpathSync(process.cwd()); const resolveApp = relativePath => path.resolve(appDirectory, relativePath); -let paths = { +const envPublicUrl = process.env.PUBLIC_URL; + +function ensureSlash(path, needsSlash) { + const hasSlash = path.endsWith('/'); + if (hasSlash && !needsSlash) { + return path.substr(path, path.length - 1); + } else if (!hasSlash && needsSlash) { + return `${path}/`; + } + return path; +} + +const getPublicUrl = appPackageJson => + envPublicUrl || require(appPackageJson).homepage; + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// Webpack needs to know it to put the right