From 83a3726a9fe024e15f10d6c6e9ad22694057e642 Mon Sep 17 00:00:00 2001 From: Brody McKee Date: Tue, 30 Oct 2018 14:40:33 +0100 Subject: [PATCH] Add Beamery configuration --- bin/react-scripts.js | 30 +++++- config/beamery/envs.js | 8 ++ config/beamery/jest.js | 6 ++ config/beamery/paths.js | 27 ++++++ config/beamery/prefixes.js | 16 ++++ config/env.js | 1 + config/paths.js | 13 ++- config/webpack.config.js | 109 ++++++++++++---------- config/webpackDevServer.config.js | 7 +- package.json | 12 +-- scripts/beamery/dependencies.js | 60 ++++++++++++ scripts/beamery/init.js | 88 +++++++++++++++++ scripts/beamery/typescript.js | 16 ++++ scripts/build.js | 11 ++- scripts/init.js | 19 +++- scripts/utils/verifyTypeScriptSetup.js | 12 ++- template-typescript/.editorconfig | 10 ++ template-typescript/.env | 13 +++ template-typescript/.storybook/addons.js | 3 + template-typescript/.storybook/config.js | 12 +++ template-typescript/gitignore | 5 + template-typescript/public/favicon.ico | Bin 3870 -> 0 bytes template-typescript/public/index.html | 15 --- template-typescript/public/manifest.json | 15 --- template-typescript/src/App.css | 32 ------- template-typescript/src/App.module.scss | 32 +++++++ template-typescript/src/App.test.tsx | 7 +- template-typescript/src/App.tsx | 10 +- template-typescript/src/index.full.ts | 47 ++++++++++ template-typescript/src/index.stories.tsx | 20 ++++ template-typescript/src/logo.svg | 18 +++- template-typescript/src/setupTests.ts | 1 + template/.editorconfig | 10 ++ template/.env | 13 +++ template/.storybook/addons.js | 3 + template/.storybook/config.js | 12 +++ template/gitignore | 5 + template/public/favicon.ico | Bin 3870 -> 0 bytes template/public/index.html | 15 --- template/public/manifest.json | 15 --- template/src/App.css | 32 ------- template/src/App.js | 10 +- template/src/App.module.scss | 32 +++++++ template/src/App.test.js | 7 +- template/src/index.css | 6 +- template/src/index.full.js | 46 +++++++++ template/src/index.stories.js | 23 +++++ template/src/logo.svg | 18 +++- template/src/setupTests.js | 1 + webpack.config.prod.js | 5 + 50 files changed, 701 insertions(+), 227 deletions(-) create mode 100644 config/beamery/envs.js create mode 100644 config/beamery/jest.js create mode 100644 config/beamery/paths.js create mode 100644 config/beamery/prefixes.js create mode 100644 scripts/beamery/dependencies.js create mode 100644 scripts/beamery/init.js create mode 100644 scripts/beamery/typescript.js create mode 100644 template-typescript/.editorconfig create mode 100644 template-typescript/.env create mode 100644 template-typescript/.storybook/addons.js create mode 100644 template-typescript/.storybook/config.js delete mode 100644 template-typescript/public/favicon.ico delete mode 100644 template-typescript/public/manifest.json delete mode 100644 template-typescript/src/App.css create mode 100644 template-typescript/src/App.module.scss create mode 100644 template-typescript/src/index.full.ts create mode 100644 template-typescript/src/index.stories.tsx create mode 100644 template-typescript/src/setupTests.ts create mode 100644 template/.editorconfig create mode 100644 template/.env create mode 100644 template/.storybook/addons.js create mode 100644 template/.storybook/config.js delete mode 100644 template/public/favicon.ico delete mode 100644 template/public/manifest.json delete mode 100644 template/src/App.css create mode 100644 template/src/App.module.scss create mode 100644 template/src/index.full.js create mode 100644 template/src/index.stories.js create mode 100644 template/src/setupTests.js create mode 100644 webpack.config.prod.js diff --git a/bin/react-scripts.js b/bin/react-scripts.js index 84cc59b7253..2c135d7f72a 100755 --- a/bin/react-scripts.js +++ b/bin/react-scripts.js @@ -19,11 +19,37 @@ const spawn = require('react-dev-utils/crossSpawn'); const args = process.argv.slice(2); const scriptIndex = args.findIndex( - x => x === 'build' || x === 'eject' || x === 'start' || x === 'test' + x => + x.startsWith('build') || + x === 'eject' || + x.startsWith('start') || + x === 'test' ); -const script = scriptIndex === -1 ? args[0] : args[scriptIndex]; +let script = scriptIndex === -1 ? args[0] : args[scriptIndex]; const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : []; +// BMR_ENV config +const envs = require('../config/beamery/envs'); +switch (script) { + case 'build': + process.env.BMR_ENV = envs.PRODUCTION; + break; + case 'build-dev': + script = 'build'; + process.env.BMR_ENV = envs.DEVELOPMENT; + break; + case 'start-dev': + script = 'start'; + process.env.BMR_ENV = envs.DEVELOPMENT; + break; + case 'build-stg': + script = 'build'; + process.env.BMR_ENV = envs.STAGING; + break; + default: + process.env.BMR_ENV = envs.INDEPENDENT; +} + switch (script) { case 'build': case 'eject': diff --git a/config/beamery/envs.js b/config/beamery/envs.js new file mode 100644 index 00000000000..e59a135847f --- /dev/null +++ b/config/beamery/envs.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = { + DEVELOPMENT: 'development', + PRODUCTION: 'production', + STAGING: 'staging', + INDEPENDENT: 'independent', +}; diff --git a/config/beamery/jest.js b/config/beamery/jest.js new file mode 100644 index 00000000000..d67547f1312 --- /dev/null +++ b/config/beamery/jest.js @@ -0,0 +1,6 @@ +'use strict'; + +var enzyme = require('enzyme'); +var Adapter = require('enzyme-adapter-react-16'); + +enzyme.configure({ adapter: new Adapter() }); diff --git a/config/beamery/paths.js b/config/beamery/paths.js new file mode 100644 index 00000000000..4cb1747062e --- /dev/null +++ b/config/beamery/paths.js @@ -0,0 +1,27 @@ +'use strict'; + +const envs = require('./envs'); + +const paths = { + buildPath: 'dist', + publicPath: false, + appIndexJs: 'src/index.full', +}; + +switch (process.env.BMR_ENV) { + case envs.PRODUCTION: + paths.publicPath = 'https://storage.googleapis.com/beamery/'; + break; + case envs.STAGING: + paths.buildPath = '../app-bath/dist'; + break; + case envs.DEVELOPMENT: + paths.buildPath = '../app-bath/dev'; + break; + case envs.INDEPENDENT: + default: + paths.appIndexJs = 'src/index'; + break; +} + +module.exports = paths; diff --git a/config/beamery/prefixes.js b/config/beamery/prefixes.js new file mode 100644 index 00000000000..8761dad1461 --- /dev/null +++ b/config/beamery/prefixes.js @@ -0,0 +1,16 @@ +'use strict'; + +const paths = require('../paths'); +const appPackageJson = require(paths.appPackageJson); + +// Use the `package.json` app name to simplify setup. +const appName = appPackageJson.name; +process.env.BMR_APP_NAME = appName; + +module.exports = { + // Webpack allows us to define a path in sources. This can be useful for + // debugging against other applications. + devtoolRoot: appName ? appName + ':///' : '', + // This prefix is not used for `independent` builds. + filenamePrefix: appName ? appName : 'APP-NAME-UNDEFINED', +}; diff --git a/config/env.js b/config/env.js index 7565cecd001..8f3a04d73a6 100644 --- a/config/env.js +++ b/config/env.js @@ -85,6 +85,7 @@ function getClientEnvironment(publicUrl) { // This should only be used as an escape hatch. Normally you would put // images into the `src` and `import` them in code to get their paths. PUBLIC_URL: publicUrl, + APP_NAME: process.env.BMR_APP_NAME, } ); // Stringify all values so we can feed into Webpack DefinePlugin diff --git a/config/paths.js b/config/paths.js index b719054583b..46c24402143 100644 --- a/config/paths.js +++ b/config/paths.js @@ -11,6 +11,7 @@ const path = require('path'); const fs = require('fs'); const url = require('url'); +const beameryPaths = require('./beamery/paths'); // Make sure any symlinks in the project folder are resolved: // https://github.com/facebook/create-react-app/issues/637 @@ -42,7 +43,9 @@ const getPublicUrl = appPackageJson => function getServedPath(appPackageJson) { const publicUrl = getPublicUrl(appPackageJson); const servedUrl = - envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/'); + beameryPaths.publicPath || + envPublicUrl || + (publicUrl ? url.parse(publicUrl).pathname : '/'); return ensureSlash(servedUrl, true); } @@ -77,10 +80,10 @@ const resolveModule = (resolveFn, filePath) => { module.exports = { dotenv: resolveApp('.env'), appPath: resolveApp('.'), - appBuild: resolveApp('build'), + appBuild: resolveApp(beameryPaths.buildPath), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), - appIndexJs: resolveModule(resolveApp, 'src/index'), + appIndexJs: resolveModule(resolveApp, beameryPaths.appIndexJs), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), @@ -99,10 +102,10 @@ const resolveOwn = relativePath => path.resolve(__dirname, '..', relativePath); module.exports = { dotenv: resolveApp('.env'), appPath: resolveApp('.'), - appBuild: resolveApp('build'), + appBuild: resolveApp(beameryPaths.buildPath), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), - appIndexJs: resolveModule(resolveApp, 'src/index'), + appIndexJs: resolveModule(resolveApp, beameryPaths.appIndexJs), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appTsConfig: resolveApp('tsconfig.json'), diff --git a/config/webpack.config.js b/config/webpack.config.js index ed85b555ea6..d4502f8da21 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -15,14 +15,14 @@ const resolve = require('resolve'); const PnpWebpackPlugin = require('pnp-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); +// const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); const TerserPlugin = require('terser-webpack-plugin'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +// const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const safePostCssParser = require('postcss-safe-parser'); -const ManifestPlugin = require('webpack-manifest-plugin'); -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); +// const ManifestPlugin = require('webpack-manifest-plugin'); +// const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); +// const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); @@ -34,12 +34,13 @@ const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); // @remove-on-eject-begin const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); // @remove-on-eject-end +const beameryConfig = require('./beamery/prefixes'); // Source maps are resource heavy and can cause out of memory issue for large source files. const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; // Some apps do not need the benefits of saving a web request, so not inlining the chunk // makes for a smoother build process. -const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; +// const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; // Check if TypeScript is setup const useTypeScript = fs.existsSync(paths.appTsConfig); @@ -64,7 +65,7 @@ module.exports = function(webpackEnv) { : isEnvDevelopment && '/'; // 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 === './'; + // 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. @@ -78,14 +79,15 @@ module.exports = function(webpackEnv) { // common function to get style loaders const getStyleLoaders = (cssOptions, preProcessor) => { const loaders = [ - isEnvDevelopment && require.resolve('style-loader'), + require.resolve('style-loader'), + /* isEnvDevelopment && require.resolve('style-loader'), isEnvProduction && { loader: MiniCssExtractPlugin.loader, options: Object.assign( {}, shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined ), - }, + }, */ { loader: require.resolve('css-loader'), options: cssOptions, @@ -145,8 +147,8 @@ module.exports = function(webpackEnv) { // the line below with these two lines if you prefer the stock client: // require.resolve('webpack-dev-server/client') + '?/', // require.resolve('webpack/hot/dev-server'), - isEnvDevelopment && - require.resolve('react-dev-utils/webpackHotDevClient'), + /* isEnvDevelopment && + require.resolve('react-dev-utils/webpackHotDevClient'), */ // Finally, this is your app's code: paths.appIndexJs, // We include the app code last so that if there is a runtime error during @@ -155,32 +157,40 @@ module.exports = function(webpackEnv) { ].filter(Boolean), output: { // The build folder. - path: isEnvProduction ? paths.appBuild : undefined, + path: paths.appBuild, // Add /* filename */ comments to generated require()s in the output. pathinfo: isEnvDevelopment, // There will be one main bundle, and one file per asynchronous chunk. // In development, it does not produce real files. filename: isEnvProduction - ? 'static/js/[name].[chunkhash:8].js' - : isEnvDevelopment && 'static/js/bundle.js', + ? `${beameryConfig.filenamePrefix}.[name]${ + process.env.BMR_ENV === 'development' + ? '' + : `.${process.env.CI_PIPELINE_ID}` + }.bundle.js` + : isEnvDevelopment && `${beameryConfig.filenamePrefix}.bundle.js`, // There are also additional JS chunk files if you use code splitting. - chunkFilename: isEnvProduction - ? 'static/js/[name].[chunkhash:8].chunk.js' - : isEnvDevelopment && 'static/js/[name].chunk.js', + /* chunkFilename: isEnvProduction + ? `static/js/[name].[chunkhash:8].chunk.js` + : isEnvDevelopment && + `static/js/[name].chunk.js`, */ // We inferred the "public path" (such as / or /my-project) from homepage. // We use "/" in development. publicPath: publicPath, // Point sourcemap entries to original disk location (format as URL on Windows) devtoolModuleFilenameTemplate: isEnvProduction ? info => + beameryConfig.devtoolRoot + path .relative(paths.appSrc, info.absoluteResourcePath) .replace(/\\/g, '/') : isEnvDevelopment && - (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), + (info => + beameryConfig.devtoolRoot + + path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), }, optimization: { - minimize: isEnvProduction, + minimize: isEnvProduction && process.env.BMR_ENV !== 'development', minimizer: [ // This is only used in production mode new TerserPlugin({ @@ -245,13 +255,13 @@ module.exports = function(webpackEnv) { // Automatically split vendor and commons // https://twitter.com/wSokra/status/969633336732905474 // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 - splitChunks: { + /* splitChunks: { chunks: 'all', name: false, - }, - // Keep the runtime chunk separated to enable long term caching + }, */ + // Keep the runtime chunk seperated to enable long term caching // https://twitter.com/wSokra/status/969679223278505985 - runtimeChunk: true, + // runtimeChunk: true, }, resolve: { // This allows you to set a fallback for where Webpack should look for modules. @@ -333,11 +343,11 @@ module.exports = function(webpackEnv) { // smaller than specified limit in bytes as data URLs to avoid requests. // A missing `test` is equivalent to a match. { - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], + test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/], loader: require.resolve('url-loader'), options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', + // limit: 10000, + name: `static/media/[name].[hash:8].[ext]`, }, }, // Process application JS with Babel. @@ -507,7 +517,7 @@ module.exports = function(webpackEnv) { // by webpacks internal loaders. exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], options: { - name: 'static/media/[name].[hash:8].[ext]', + name: `static/media/[name].[hash:8].[ext]`, }, }, // ** STOP ** Are you adding a new loader? @@ -518,14 +528,15 @@ module.exports = function(webpackEnv) { }, plugins: [ // Generates an `index.html` file with the