Skip to content

Instantly share code, notes, and snippets.

@stringparser
Last active November 2, 2021 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save stringparser/352e5cc0afb5586887c6361baff4ed66 to your computer and use it in GitHub Desktop.
Save stringparser/352e5cc0afb5586887c6361baff4ed66 to your computer and use it in GitHub Desktop.
webpack + typescript + react config #blog

react, typescript, redux, webpack

Bootstrapped with Create React App Typescript and customized.

stack and setup

For more details see package.json.

scripts

  • Install dependencies with npm install
  • Fix lint errors with npm run lint:fix (or find out how to automatically do this using your editor on save)
'use strict';
let NODE_ENV = process.env.NODE_ENV;
// Do this as the first thing so that any code reading it knows the right env.
process.env.NODE_ENV = NODE_ENV = NODE_ENV ||  'development';
process.env.BABEL_ENV = NODE_ENV;
console.log('[info] process.env.NODE_ENV', process.env.NODE_ENV);
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const fs = require('fs');
const cp = require('child_process');
const path = require('path');
const util = require('./util');
const paths = require('./paths');
let APP_VERSION = cp.execSync(
'echo $(git tag | grep "\d*\.\d*\.\d*" | sort -r | head -n1)-$(git rev-parse HEAD)'
).toString('utf-8').trim();
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv').config({
path: dotenvFile,
});
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(PUBLIC_URL) {
const {
SUPPLY_API,
CSV_SERVICE,
AUTH_VERSION
} = process.env;
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
SUPPLY_API,
CSV_SERVICE,
AUTH_VERSION,
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV,
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// 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,
APP_VERSION,
}
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;
{
"version": "0.1.0",
"private": true,
"scripts": {
"test": "node scripts/test",
"start": "node $NODE_FLAGS scripts/start",
"build": "node scripts/build",
"serve": "node static-server",
"lint": "tslint --config tslint.json --project tsconfig.json",
"lint:fix": "npm run lint -- --fix"
},
"dependencies": {
"@types/express": "^4.0.38",
"@types/react": "^16.0.19",
"@types/react-dom": "^16.0.2",
"@types/react-router-dom": "^4.2.1",
"express": "^4.15.4",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router-dom": "^4.2.2"
},
"devDependencies": {
"@types/chalk": "^0.4.31",
"@types/history": "^4.6.0",
"@types/jest": "^20.0.8",
"@types/jwt-decode": "^2.2.1",
"@types/lodash.sortby": "^4.7.3",
"@types/node": "^8.0.27",
"@types/node-fetch": "^1.6.7",
"@types/react-icons": "^2.2.2",
"@types/react-redux": "^5.0.9",
"@types/react-router": "^4.0.19",
"@types/redux-actions": "^2.2.0",
"app-root-path": "^2.0.1",
"autoprefixer": "7.1.1",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react-app": "^3.0.2",
"bootstrap": "^4.0.0-beta",
"case-sensitive-paths-webpack-plugin": "2.1.1",
"chalk": "1.1.3",
"cli-highlight": "1.1.4",
"css-loader": "0.28.4",
"dotenv": "4.0.0",
"extract-text-webpack-plugin": "2.1.2",
"file-loader": "0.11.2",
"fs-extra": "3.0.1",
"history": "^4.7.2",
"html-webpack-plugin": "2.28.0",
"jest": "20.0.3",
"lodash.sortby": "^4.7.0",
"node-fetch": "^1.7.3",
"node-sass": "^4.5.3",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.0.0",
"postcss-loader": "2.0.5",
"promise": "7.1.1",
"react-dev-utils": "^3.0.1",
"react-error-overlay": "^1.0.8",
"react-icons": "^2.2.5",
"react-lazy-import": "^0.1.1",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"redux": "^3.7.2",
"redux-actions": "^2.2.1",
"redux-devtools-extension": "^2.13.2",
"redux-thunk": "^2.2.0",
"sass-loader": "^6.0.6",
"source-map-loader": "^0.2.1",
"style-loader": "0.18.2",
"sw-loader": "^0.1.1",
"ts-jest": "^20.0.7",
"ts-loader": "^2.2.1",
"ts-node": "^3.3.0",
"tslint": "^5.2.0",
"tslint-loader": "^3.5.3",
"tslint-react": "^3.0.0",
"typescript": "~2.4.0",
"url-loader": "0.5.8",
"webpack": "2.6.1",
"webpack-dev-server": "2.5.0",
"webpack-hot-middleware": "^2.20.0",
"webpack-manifest-plugin": "1.1.0",
"whatwg-fetch": "^2.0.3"
},
"jest": {
"mapCoverage": true,
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}"
],
"setupFiles": [
"<rootDir>/config/polyfills.js"
],
"moduleFileExtensions": [
"web.ts",
"ts",
"web.tsx",
"tsx",
"web.js",
"js",
"web.jsx",
"jsx",
"json"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.test.ts?(x)",
"<rootDir>/src/**/?(*.)(spec|test).ts?(x)"
],
"testEnvironment": "jsdom",
"testURL": "http://localhost",
"transform": {
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^.+\\.tsx?$": "<rootDir>/config/jest/typescriptTransform.js",
"^(?!.*\\.(css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
},
"globals": {
"ts-jest": {
"skipBabel": true,
"tsConfigFile": "tsconfig.json"
}
}
},
"babel": {
"presets": [
[
"env",
{
"targets": {
"browsers": [
"Android >= 4.4",
"iOS >= 9.3",
"Chrome >= 42",
"Firefox >= 42",
"Safari >= 9",
"IE >= 11",
"Edge >= 12",
"Opera >= 30"
]
},
"useBuiltIns": true
}
],
"react-app"
]
},
"eslintConfig": {
"extends": "react-app"
}
}
'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);
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}/`;
} else {
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 <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl =
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
return ensureSlash(servedUrl, true);
}
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('src/index.html'),
appIndexJs: resolveApp('src/main.tsx'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveApp('src/setupTests.ts'),
appNodeModules: resolveApp('node_modules'),
appTsConfig: resolveApp('tsconfig.json'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json'))
};
{
"include": [
"./src/**/*",
"./scripts/**/*"
],
"compileOnSave": true,
"compilerOptions": {
"jsx": "react",
"target": "es6",
"outDir": "build/dist",
"module": "esnext",
"allowJs": true,
"rootDirs": [
"src",
"scripts"
],
"sourceMap": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"moduleResolution": "node",
"strictNullChecks": true,
"noImplicitReturns": true,
"allowSyntheticDefaultImports": true,
"suppressImplicitAnyIndexErrors": true,
"forceConsistentCasingInFileNames": true
}
}
{
"extends": [ "tslint-react" ],
"rules": {
"align": [
true,
"parameters"
],
"ban": false,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": false,
"forin": true,
"indent": [ true, "spaces" ],
"interface-name": [true, "never-prefix"],
"jsx-alignment": false,
"jsx-no-lambda": false,
"jsx-no-string-ref": false,
"jsx-no-multiline-js": false,
"label-position": true,
"max-line-length": [ true, 120 ],
"no-any": false,
"no-arg": true,
"no-bitwise": true,
"no-console": [
false,
"log",
"warning",
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": false,
"no-unused-expression": true,
"one-line": [
true,
"check-catch",
"check-else",
"check-open-brace",
"check-whitespace"
],
"quotemark": [true, "single", "jsx-double"],
"radix": true,
"semicolon": [true, "always"],
"switch-default": true,
"trailing-comma": false,
"triple-equals": [ true, "allow-null-check" ],
"typedef": [
true,
"parameter",
"property-declaration"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": [
true,
"ban-keywords",
"check-format",
"allow-leading-underscore",
"allow-snake-case",
"allow-pascal-case"
],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-module",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
}
}
exports = module.exports = {
isProduction() {
return process.env.NODE_ENV === 'production';
},
isDevelopment() {
return process.env.NODE_ENV === 'development';
}
};
const isProduction = process.env.NODE_ENV === 'production';
const isDevelopment = process.env.NODE_ENV === 'development';
// assert the environment
if (!isProduction && !isDevelopment) {
throw new Error('NODE_ENV is not set to development or production, please set an environment for the build');
}
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const ManifestPlugin = require('webpack-manifest-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const paths = require('./paths');
const packageJson = require('../package');
const getClientEnvironment = require('./env');
// get the browser list from the babel configuration
const browserList = packageJson.babel.presets.filter((v) => {
return Array.isArray(v) && v[0] === 'env' && v[1] && v[1].targets;
}).reduce(function (_, envPreset) {
if (envPreset[1].targets.browsers) {
return envPreset[1].targets.browsers
} else {
return _; // fallback to browserlist below
}
},
[
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
]
);
// 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 = isDevelopment ? '/' : 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_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = isDevelopment ? '' : publicPath.slice(0, -1);
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// Assert this just to be safe.
// Development builds of React are slow and not intended for production.
if (isProduction && env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
// Note: defined here because it will be used more than once.
const cssFilename = 'static/css/[name]-[contenthash].css';
// plugin that will extract the css declared in our js filess
const extractSASS = new ExtractTextPlugin({
filename: cssFilename,
allChunks: true
});
// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// To have this structure working with relative paths, we have to use custom options.
const extractTextPluginOptions = shouldUseRelativeAssetPaths
? // Making sure that the publicPath goes back to to build folder.
{ publicPath: Array(cssFilename.split('/').length).join('../') }
: {}
;
exports = module.exports = {
// Don't attempt to continue if there are any errors.
bail: isProduction,
// We generate sourcemaps in production. This is slow but gives good results.
// You can exclude the *.map files from the build during deployment.
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
devtool: isProduction ? 'source-map' : '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.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.
entry: [
// We ship a few polyfills by default:
require.resolve('./polyfills'),
// dev: Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// 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'),
isDevelopment && require.resolve('react-dev-utils/webpackHotDevClient'),
// dev: Errors should be considered fatal in development
isDevelopment && require.resolve('react-error-overlay'),
// Finally, this is your app's code:
paths.appIndexJs,
// dev: We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(v => v),
output: {
// dev: Next line is not used in dev but WebpackDevServer crashes without it:
// prod: The build folder.
path: paths.appBuild,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: isDevelopment,
// dev: This does not produce a real file. It's just the virtual path that is
// served by WebpackDevServer in development. This is the JS bundle
// containing code from all our entry points, and the Webpack runtime.
// prod: Generated JS file names (with nested folders).
// There will be one main bundle, and one file per asynchronous chunk.
// We don't currently advertise code splitting but Webpack supports it.
filename: 'static/js/[name]-[hash].js',
// There are also additional JS chunk files if you use code splitting.
chunkFilename: 'static/js/chunk-[name]-[hash].js',
// This is the URL that app is served from. We use "/" in development.
publicPath: publicPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info => {
if (isProduction) {
return path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
;
} else {
return path.resolve(info.absoluteResourcePath).replace(/\\/g, '/');
}
},
},
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/facebookincubator/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean),
// add the CWD node_modules
path.join(process.cwd(), 'node_modules')
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: [
'.web.ts',
'.ts',
'.web.tsx',
'.tsx',
'.web.js',
'.js',
'.json',
'.web.jsx',
'.jsx',
],
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc),
],
},
module: {
strictExportPresence: true,
rules: [
// TODO: Disable require.ensure as it's not a standard language feature.
// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
// { parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.tsx?$/,
loader: require.resolve('tslint-loader'),
enforce: 'pre',
include: paths.appSrc,
options: Object.assign({}, require('../tslint.json'), {
sourceMap: true,
tsConfigFile: require.resolve('../tsconfig.json')
}),
},
{
test: /\.tsx?$/,
include: paths.appSrc,
use: [
{
loader: require.resolve('babel-loader'),
options: Object.assign({}, packageJson.babel, {
sourceMap: true
}),
},
{
loader: require.resolve('ts-loader')
}
]
},
{
test: /\.jsx?$/,
include: [
paths.appSrc,
path.resolve('.', 'node_modules', 'react-icons')
],
use: [
{
loader: require.resolve('babel-loader'),
options: Object.assign({}, packageJson.babel, {
sourceMap: true
}),
}
]
},
// ** ADDING/UPDATING LOADERS **
// The "file" loader handles all assets unless explicitly excluded.
// The `exclude` list *must* be updated with every change to loader extensions.
// When adding a new loader, you must add its `test`
// as a new entry in the `exclude` list for "file" loader.
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
{
exclude: [
/\.html$/,
// We have to write /\.(js|jsx)(\?.*)?$/ rather than just /\.(js|jsx)$/
// because you might change the hot reloading server from the custom one
// to Webpack's built-in webpack-dev-server/client?/, which would not
// get properly excluded by /\.(js|jsx)$/ because of the query string.
// Webpack 2 fixes this, but for now we include this hack.
// https://github.com/facebookincubator/create-react-app/issues/1713
/\.(js|jsx)(\?.*)?$/,
/\.(ts|tsx)(\?.*)?$/,
/\.css$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
/\.jpe?g$/,
/\.png$/,
],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name]-[hash].[ext]',
},
},
// "url" loader works like "file" loader except that it embeds assets
// 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)$/,
loader: require.resolve('url-loader'),
options: {
name: 'static/media/[name]-[hash].[ext]',
limit: 10000,
},
},
// "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 <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.scss$/,
include: paths.appSrc,
use: extractSASS.extract(
Object.assign(
{
fallback: require.resolve('style-loader'),
use: [
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
minimize: isProduction,
sourceMap: true,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
flexbox: 'no-2009',
browsers: browserList,
}),
],
sourceMap: true
},
},
{
loader: require.resolve('sass-loader'),
options: {
sourceMap: true
}
}
],
},
extractTextPluginOptions
)
),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
// ** STOP ** Are you adding a new loader?
// Remember to add the new extension(s) to the "url" loader exclusion list.
],
},
plugins: [
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In development, this will be an empty string.
// In production, it will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(env.raw),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: 'body',
chunks: [ 'main' ],
template: paths.appHtml,
minify: isProduction ? {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
} : {}
}),
// Add module names to factory functions so they appear in browser profiler.
new webpack.NamedModulesPlugin(),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
// Minify the code.
isProduction && new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebookincubator/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
},
output: {
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebookincubator/create-react-app/issues/2488
ascii_only: true,
},
sourceMap: true,
}),
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
extractSASS,
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240
isDevelopment && new CaseSensitivePathsPlugin(),
// If you require a missing module and then `npm install` it, you still have
// to restart the development server for Webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebookincubator/create-react-app/issues/186
isDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules),
// Generate a manifest file which contains a mapping of all asset filenames
// to their corresponding output file so that tools can pick it up without
// having to parse `index.html`.
isProduction && new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
isProduction && new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
].filter((v) => v),
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment