diff --git a/.env b/.env
deleted file mode 100644
index 38aee11b..00000000
--- a/.env
+++ /dev/null
@@ -1 +0,0 @@
-HTTPS=true
\ No newline at end of file
diff --git a/.env.development b/.env.development
new file mode 100644
index 00000000..c370e8e7
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,7 @@
+PUBLIC_URL=/
+
+REACT_APP_CLIENT_V3_HOST=http://localhost:3001
+REACT_APP_API_HOST=http://localhost:5002/
+
+REACT_APP_GRAPHQL_HOST=http://localhost:5002/
+REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/
\ No newline at end of file
diff --git a/.env.production b/.env.production
new file mode 100644
index 00000000..034cf768
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,7 @@
+PUBLIC_URL=/
+
+REACT_APP_CLIENT_V3_HOST=http://localhost:3001
+REACT_APP_API_HOST=http://localhost:5002/
+
+REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/
+REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 98db1db6..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,22 +0,0 @@
-module.exports = {
- parser: '@typescript-eslint/parser',
- extends: ['plugin:@typescript-eslint/recommended', 'react-app', 'prettier'],
- plugins: ['@typescript-eslint', 'react'],
- rules: {
- 'react/jsx-filename-extension': [
- 1,
- { extensions: ['.js', '.jsx', 'tsx', 'ts'] },
- ],
- '@typescript-eslint/indent': 0,
- '@typescript-eslint/no-empty-interface': 0,
- 'import/first': 0,
- '@typescript-eslint/explicit-function-return-type': 0,
- '@typescript-eslint/explicit-member-accessibility': 0,
- '@typescript-eslint/prefer-interface': 0,
- '@typescript-eslint/no-use-before-define': 0,
- '@typescript-eslint/no-non-null-assertion': 0,
- '@typescript-eslint/no-explicit-any': 0,
- 'no-use-before-define': 0,
- '@typescript-eslint/camelcase': 0,
- },
-};
diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
new file mode 100644
index 00000000..2a95e2f9
--- /dev/null
+++ b/.github/workflows/dev.yml
@@ -0,0 +1,62 @@
+name: Deploy Serverless SSR (Dev)
+
+on:
+ push:
+ branches:
+ - develop
+
+jobs:
+ deploy:
+ name: deploy
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Get yarn cache
+ id: yarn-cache
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v1
+ with:
+ path: ${{ steps.yarn-cache.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+ - name: yarn install
+ uses: borales/actions-yarn@v2.0.0
+ with:
+ cmd: install
+ - name: npm run build:ci
+ run: npm run build:ci
+ env:
+ REACT_APP_API_HOST: 'https://v2.velog.io/'
+ PUBLIC_URL: 'https://d3v0gm8v6v8olv.cloudfront.net/'
+ STAGE: true
+ - name: s3 sync
+ uses: jakejarvis/s3-sync-action@master
+ with:
+ args: --follow-symlinks --delete
+ env:
+ AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET_DEV }}
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }}
+ AWS_REGION: 'ap-northeast-2'
+ SOURCE_DIR: 'build'
+
+ - name: serverless deploy
+ uses: serverless/github-action@master
+ with:
+ args: deploy
+ env:
+ # or if using AWS creds directly
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }}
+ REACT_APP_API_HOST: 'https://v2.velog.io/'
+ PUBLIC_URL: 'https://d3v0gm8v6v8olv.cloudfront.net/'
+ STAGE: true
+ - name: Slack Notification
+ uses: rtCamp/action-slack-notify@v2.0.0
+ env:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ SLACK_USERNAME: 'Github Actions'
+ SLACK_ICON: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'
+ SLACK_MESSAGE: '*stage: dev* - 벨로그 웹 클라이언트 배포가 끝났어요! :rocket:'
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..660d8f68
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,52 @@
+name: Deploy
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ deploy:
+ name: deploy
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+ - name: Setup Node.js 16.x
+ uses: actions/setup-node@v2
+ with:
+ node-version: '16.x'
+ - name: Get yarn cache
+ id: yarn-cache
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+
+ - uses: actions/cache@v3
+ with:
+ path: ${{ steps.yarn-cache.outputs.dir }}
+ key: ${{ runner.os }}-yarn-v1-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+ - name: yarn install
+ uses: borales/actions-yarn@v4.0.0
+ with:
+ cmd: install
+ - name: npm run build:ci
+ run: npm run build:ci
+ env:
+ REACT_APP_API_HOST: 'https://v2.velog.io/'
+ REACT_APP_GRAPHQL_HOST: 'https://v2.velog.io/'
+ REACT_APP_GRAPHQL_HOST_NOCDN: 'https://v2.velog.io/'
+ PUBLIC_URL: 'https://static.velog.io/'
+ REACT_APP_REDIS_HOST: ${{ secrets.REDIS_HOST }}
+ REACT_APP_CLIENT_V3_HOST: 'https://velog.io/'
+ REACT_APP_WHITELIST_IPS: ${{ secrets.REACT_APP_WHITELIST_IPS }}
+ CI: false
+ - name: upload
+ env:
+ S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
+ S3_BUCKET_SSR: ${{ secrets.AWS_S3_BUCKET_SSR }}
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }}
+ AWS_REGION: 'ap-northeast-2'
+ run: |
+ yarn upload
+ yarn upload:ssr
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 34663306..0516f767 100755
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,15 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
-/dist
\ No newline at end of file
+/dist
+
+# package directories
+jspm_packages
+
+# Serverless directories
+.serverless
+.webpack
+
+# ignore setting
+.idea
+.vscode
diff --git a/README.md b/README.md
index 590dae5a..76a9a43c 100755
--- a/README.md
+++ b/README.md
@@ -1,3 +1,20 @@
## velog-client
-NEXT CLIENT FOR VELOG
\ No newline at end of file
+> Velog is a blog platform for developers. It provides compfy markdown editor with syntax highlighter enabled. Currently, this service only supports Korean language.
+
+Website link: https://velog.io/
+
+Backend project of service is at another Repo - [velog-backend](https://github.com/velopert/velog-server)
+
+### Project Stack
+
+- React
+- React Router
+- TypeScript
+- Redux
+- Apollo GraphQL
+- Styled Components
+- Remark
+- Codemirror
+- Serverless Framework
+- AWS Lambda
diff --git a/asset-license.md b/asset-license.md
index 89cef52a..db7d2bd0 100644
--- a/asset-license.md
+++ b/asset-license.md
@@ -3,4 +3,9 @@ Icons made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [ww
-
\ No newline at end of file
+
+
+
+Heart Icon: https://iconmonstr.com/favorite-8-svg/
+Clip Icon: https://iconmonstr.com/paperclip-2-svg/
+Check Icon: https://iconmonstr.com/check-mark-1-svg/
\ No newline at end of file
diff --git a/config/env.js b/config/env.js
index 3e22182c..3ec40919 100644
--- a/config/env.js
+++ b/config/env.js
@@ -1,5 +1,3 @@
-
-
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
@@ -15,7 +13,7 @@ if (!NODE_ENV) {
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
-var dotenvFiles = [
+const dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
@@ -77,7 +75,6 @@ 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_ENV: process.env.APP_ENV || 'browser',
},
);
// Stringify all values so we can feed into Webpack DefinePlugin
@@ -88,7 +85,12 @@ function getClientEnvironment(publicUrl) {
}, {}),
};
- return { raw, stringified };
+ const stringifiedForServerless = Object.keys(raw).reduce((env, key) => {
+ env[`process.env.${key}`] = JSON.stringify(raw[key]);
+ return env;
+ }, {});
+
+ return { raw, stringified, stringifiedForServerless };
}
module.exports = getClientEnvironment;
diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js
index 07010e33..aab67618 100644
--- a/config/jest/fileTransform.js
+++ b/config/jest/fileTransform.js
@@ -1,6 +1,7 @@
'use strict';
const path = require('path');
+const camelcase = require('camelcase');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
@@ -10,17 +11,26 @@ module.exports = {
const assetFilename = JSON.stringify(path.basename(filename));
if (filename.match(/\.svg$/)) {
- return `module.exports = {
+ // Based on how SVGR generates a component name:
+ // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
+ const pascalCaseFilename = camelcase(path.parse(filename).name, {
+ pascalCase: true,
+ });
+ const componentName = `Svg${pascalCaseFilename}`;
+ return `const React = require('react');
+ module.exports = {
__esModule: true,
default: ${assetFilename},
- ReactComponent: (props) => ({
- $$typeof: Symbol.for('react.element'),
- type: 'svg',
- ref: null,
- key: null,
- props: Object.assign({}, props, {
- children: ${assetFilename}
- })
+ ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
+ return {
+ $$typeof: Symbol.for('react.element'),
+ type: 'svg',
+ ref: ref,
+ key: null,
+ props: Object.assign({}, props, {
+ children: ${assetFilename}
+ })
+ };
}),
};`;
}
diff --git a/config/modules.js b/config/modules.js
new file mode 100644
index 00000000..c8efd0dd
--- /dev/null
+++ b/config/modules.js
@@ -0,0 +1,141 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+const chalk = require('react-dev-utils/chalk');
+const resolve = require('resolve');
+
+/**
+ * Get additional module paths based on the baseUrl of a compilerOptions object.
+ *
+ * @param {Object} options
+ */
+function getAdditionalModulePaths(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ // We need to explicitly check for null and undefined (and not a falsy value) because
+ // TypeScript treats an empty string as `.`.
+ if (baseUrl == null) {
+ // If there's no baseUrl set we respect NODE_PATH
+ // Note that NODE_PATH is deprecated and will be removed
+ // in the next major release of create-react-app.
+
+ const nodePath = process.env.NODE_PATH || '';
+ return nodePath.split(path.delimiter).filter(Boolean);
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
+ // the default behavior.
+ if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Allow the user set the `baseUrl` to `appSrc`.
+ if (path.relative(paths.appSrc, baseUrlResolved) === '') {
+ return [paths.appSrc];
+ }
+
+ // If the path is equal to the root directory we ignore it here.
+ // We don't want to allow importing from the root directly as source files are
+ // not transpiled outside of `src`. We do allow importing them with the
+ // absolute path (e.g. `src/Components/Button.js`) but we set that up with
+ // an alias.
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Otherwise, throw an error.
+ throw new Error(
+ chalk.red.bold(
+ "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
+ ' Create React App does not support other values at this time.'
+ )
+ );
+}
+
+/**
+ * Get webpack aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getWebpackAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ src: paths.appSrc,
+ };
+ }
+}
+
+/**
+ * Get jest aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getJestAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ '^src/(.*)$': '/src/$1',
+ };
+ }
+}
+
+function getModules() {
+ // Check if TypeScript is setup
+ const hasTsConfig = fs.existsSync(paths.appTsConfig);
+ const hasJsConfig = fs.existsSync(paths.appJsConfig);
+
+ if (hasTsConfig && hasJsConfig) {
+ throw new Error(
+ 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
+ );
+ }
+
+ let config;
+
+ // If there's a tsconfig.json we assume it's a
+ // TypeScript project and set up the config
+ // based on tsconfig.json
+ if (hasTsConfig) {
+ const ts = require(resolve.sync('typescript', {
+ basedir: paths.appNodeModules,
+ }));
+ config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
+ // Otherwise we'll check if there is jsconfig.json
+ // for non TS projects.
+ } else if (hasJsConfig) {
+ config = require(paths.appJsConfig);
+ }
+
+ config = config || {};
+ const options = config.compilerOptions || {};
+
+ const additionalModulePaths = getAdditionalModulePaths(options);
+
+ return {
+ additionalModulePaths: additionalModulePaths,
+ webpackAliases: getWebpackAliases(options),
+ jestAliases: getJestAliases(options),
+ hasTsConfig,
+ };
+}
+
+module.exports = getModules();
diff --git a/config/paths.js b/config/paths.js
index 62e134c8..98742e73 100644
--- a/config/paths.js
+++ b/config/paths.js
@@ -74,14 +74,17 @@ module.exports = {
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
+ appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
- ssrIndexJs: resolveApp('src/server'),
+ ssrIndexJs: resolveApp('src/index.server.ts'),
+ ssrServerlessEntry: resolveApp('src/serverless.ts'),
ssrBuild: resolveApp('dist'),
+ ssrServerlessBuild: resolveApp('.webpack'),
};
module.exports.moduleFileExtensions = moduleFileExtensions;
diff --git a/config/pnpTs.js b/config/pnpTs.js
new file mode 100644
index 00000000..d1b0539f
--- /dev/null
+++ b/config/pnpTs.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const { resolveModuleName } = require('ts-pnp');
+
+exports.resolveModuleName = (
+ typescript,
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost
+) => {
+ return resolveModuleName(
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost,
+ typescript.resolveModuleName
+ );
+};
+
+exports.resolveTypeReferenceDirective = (
+ typescript,
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost
+) => {
+ return resolveModuleName(
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost,
+ typescript.resolveTypeReferenceDirective
+ );
+};
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 6d6b34ed..37d9638b 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -1,4 +1,3 @@
-/* eslint-disable */
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
@@ -18,13 +17,16 @@ const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeM
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const paths = require('./paths');
+const modules = require('./modules');
const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
-const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
+const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
const LoadablePlugin = require('@loadable/webpack-plugin');
-const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
- .BundleAnalyzerPlugin;
+
+const postcssNormalize = require('postcss-normalize');
+
+const appPackageJson = require(paths.appPackageJson);
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
@@ -32,6 +34,10 @@ const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
+const imageInlineSizeLimit = parseInt(
+ process.env.IMAGE_INLINE_SIZE_LIMIT || '10000',
+);
+
// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);
@@ -47,6 +53,11 @@ module.exports = function(webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development';
const isEnvProduction = webpackEnv === 'production';
+ // Variable used for enabling profiling in Production
+ // passed into alias object. Uses a flag if passed into the build command
+ const isEnvProductionProfile =
+ isEnvProduction && process.argv.includes('--profile');
+
// 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.
// In development, we always serve from the root. This makes config easier.
@@ -72,10 +83,7 @@ module.exports = function(webpackEnv) {
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
- options: Object.assign(
- {},
- shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined,
- ),
+ options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
},
{
loader: require.resolve('css-loader'),
@@ -98,18 +106,30 @@ module.exports = function(webpackEnv) {
},
stage: 3,
}),
+ // Adds PostCSS Normalize as the reset css with default options,
+ // so that it honors browserslist config in package.json
+ // which in turn let's users customize the target behavior as per their needs.
+ postcssNormalize(),
],
- sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
+ sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
].filter(Boolean);
if (preProcessor) {
- loaders.push({
- loader: require.resolve(preProcessor),
- options: {
- sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
+ loaders.push(
+ {
+ loader: require.resolve('resolve-url-loader'),
+ options: {
+ sourceMap: isEnvProduction && shouldUseSourceMap,
+ },
+ },
+ {
+ loader: require.resolve(preProcessor),
+ options: {
+ sourceMap: true,
+ },
},
- });
+ );
}
return loaders;
};
@@ -122,7 +142,7 @@ module.exports = function(webpackEnv) {
? shouldUseSourceMap
? 'source-map'
: false
- : isEnvDevelopment && 'eval-source-map',
+ : isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: [
@@ -152,11 +172,13 @@ module.exports = function(webpackEnv) {
// 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'
+ ? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
+ // TODO: remove this when upgrading to webpack 5
+ futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
- ? 'static/js/[name].[chunkhash:8].chunk.js'
+ ? 'static/js/[name].[contenthash: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.
@@ -169,6 +191,12 @@ module.exports = function(webpackEnv) {
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
+ // Prevents conflicts when multiple Webpack runtimes (from different apps)
+ // are used on the same page.
+ jsonpFunction: `webpackJsonp${appPackageJson.name}`,
+ // this defaults to 'window', but by setting it to 'this' then
+ // module chunks which are built will work in web workers as well.
+ globalObject: 'this',
},
optimization: {
minimize: isEnvProduction,
@@ -177,8 +205,8 @@ module.exports = function(webpackEnv) {
new TerserPlugin({
terserOptions: {
parse: {
- // we want terser to parse ecma 8 code. However, we don't want it
- // to apply any minfication steps that turns valid ecma 5 code
+ // We want terser to parse ecma 8 code. However, we don't want it
+ // to apply any minification steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
@@ -194,13 +222,16 @@ module.exports = function(webpackEnv) {
comparisons: false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
- // Pending futher investigation:
+ // Pending further investigation:
// https://github.com/terser-js/terser/issues/120
inline: 2,
},
mangle: {
safari10: true,
},
+ // Added for profiling in devtools
+ keep_classnames: isEnvProductionProfile,
+ keep_fnames: isEnvProductionProfile,
output: {
ecma: 5,
comments: false,
@@ -209,11 +240,6 @@ module.exports = function(webpackEnv) {
ascii_only: true,
},
},
- // Use multi-process parallel running to improve the build speed
- // Default number of concurrent runs: os.cpus().length - 1
- parallel: true,
- // Enable file caching
- cache: true,
sourceMap: shouldUseSourceMap,
}),
// This is only used in production mode
@@ -242,16 +268,18 @@ module.exports = function(webpackEnv) {
},
// Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
- runtimeChunk: true,
+ // https://github.com/facebook/create-react-app/issues/5358
+ runtimeChunk: {
+ name: entrypoint => `runtime-${entrypoint.name}`,
+ },
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253
- modules: ['node_modules'].concat(
- // It is guaranteed to exist because we tweak it in `env.js`
- process.env.NODE_PATH.split(path.delimiter).filter(Boolean),
+ modules: ['node_modules', paths.appNodeModules].concat(
+ modules.additionalModulePaths || [],
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
@@ -266,6 +294,12 @@ module.exports = function(webpackEnv) {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
+ // Allows for better profiling with ReactDevTools
+ ...(isEnvProductionProfile && {
+ 'react-dom$': 'react-dom/profiling',
+ 'scheduler/tracing': 'scheduler/tracing-profiling',
+ }),
+ ...(modules.webpackAliases || {}),
},
plugins: [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
@@ -300,8 +334,10 @@ module.exports = function(webpackEnv) {
use: [
{
options: {
+ cache: true,
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
+ resolvePluginsRelativeTo: __dirname,
},
loader: require.resolve('eslint-loader'),
},
@@ -320,7 +356,7 @@ module.exports = function(webpackEnv) {
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
- limit: 10000,
+ limit: imageInlineSizeLimit,
name: 'static/media/[name].[hash:8].[ext]',
},
},
@@ -341,7 +377,8 @@ module.exports = function(webpackEnv) {
{
loaderMap: {
svg: {
- ReactComponent: '@svgr/webpack?-svgo![path]',
+ ReactComponent:
+ '@svgr/webpack?-svgo,+titleProp,+ref![path]',
},
},
},
@@ -351,7 +388,8 @@ module.exports = function(webpackEnv) {
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
- cacheCompression: isEnvProduction,
+ // See #6846 for context on why cacheCompression is disabled
+ cacheCompression: false,
compact: isEnvProduction,
},
},
@@ -372,21 +410,16 @@ module.exports = function(webpackEnv) {
],
],
cacheDirectory: true,
- cacheCompression: isEnvProduction,
+ // See #6846 for context on why cacheCompression is disabled
+ cacheCompression: false,
- // If an error happens in a package, it's possible to be
- // because it was compiled. Thus, we don't want the browser
- // debugger to show the original code. Instead, the code
- // being evaluated would be much more helpful.
- sourceMaps: false,
+ // Babel sourcemaps are needed for debugging into node_modules
+ // code. Without the options below, debuggers like VSCode
+ // show incorrect code and set breakpoints on the wrong lines.
+ sourceMaps: shouldUseSourceMap,
+ inputSourceMap: shouldUseSourceMap,
},
},
- // handles .graphql files
- {
- test: /\.(graphql|gql)$/,
- exclude: /node_modules/,
- loader: require('graphql-tag/loader'),
- },
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject