Refactor Blog: (1) Webpack
March 9, 2021
npx create-react-app
or gatsby new
. I'm writing every line of the configs by myself.webpack.config.js
, babelrc
, tsconfig.json
-- I know the feeling. I used to be afraid of dealing with them, but not anymore. I hope this article helps others to achieve that too.{
"presets": [
"@babel/preset-react",
// tell babel it has to compile React
"@babel/preset-typescript"
// tell babel it has to compile Typescript
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread",
// enables above features of JavaScript in development
"babel-plugin-styled-components"
// I used styled-components in this project, this is the plugin to help babel process it
]
}
{
"compilerOptions": {
"target": "ES5",
"module": "CommonJS",
"lib": ["DOM", "ES2020"],
"strict": true,
"noImplicitAny": true,
"moduleResolution": "Node",
"jsx": "react"
},
"include": ["src"],
"exclude": ["node_modules"]
}
.ts
files that need to be compiled.includes
, define the paths that do NOT need compiling.ES5
or a newer version without worrying about compatibility issues because babel will compile again.commonJS
for applications running on node.DOM
if features like document
or window
are used.node
to mock node's way to resolve module importing..jsx
files. Since we're developing React app, use react
.import * as webpack from "webpack";
import { resolve } from "path";
const config: webpack.Configuration = {
mode: "development",
entry: "./src/client/index.tsx",
context: resolve(__dirname),
output: {
filename: "[name].bundle.js",
path: resolve(__dirname, "dist", "static"),
},
module: {
rules: [
{
test: /\\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
},
{
loader: "ts-loader",
options: {
configFile: "tsconfig.json",
},
},
],
},
],
},
optimization: {
minimize: true,
splitChunks: {
cacheGroups: {
commons: {
test: /node_modules/,
name: "vendor",
chunks: "initial",
},
},
},
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"],
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
CONTENTFUL_TOKEN: JSON.stringify(process.env.CONTENTFUL_TOKEN || ""),
CONTENTFUL_SPACE_ID: JSON.stringify(
process.env.CONTENTFUL_SPACE_ID || ""
),
},
}),
],
devtool: "inline-source-map",
};
export default config;
process.env.NODE_ENV
on DefinePlugin
. This can be set in command line parameter --mode
too. I set this to develop
and add --mode production
in scripts for production building.index.js
in src
folder for MVVM frameworks.filename
for, well, the output filename, and path
for the output folder path..js
and .json
files, so we need to add custom loaders for packaging other types of files..ts
files, you can add configFile
in use
to specifying the typescript config you want to use.test
, specifying the file you wish not to package, like node modules.DefinePlugin
to define the environment variables in this configuration.devtool
generates a map between the output and the source, so the console logs can display which line of the source code is causing the error.import * as webpack from "webpack";
import { resolve } from "path";
import * as nodeExternals from "webpack-node-externals";
const config: webpack.Configuration = {
mode: "development",
entry: "./src/server/index.ts",
context: resolve(__dirname),
output: {
filename: "server.bundle.js",
path: resolve(__dirname, "dist", "server"),
},
target: "node",
node: {
__dirname: false,
__filename: false,
},
module: {
rules: [
{
test: /\\.tsx?$/,
exclude: /node_modules/,
use: ["babel-loader", "ts-loader"],
},
],
},
resolve: {
extensions: [".ts", ".tsx"],
},
externals: [nodeExternals()],
plugins: [
new webpack.DefinePlugin({
"process.env": {
CONTENTFUL_TOKEN: JSON.stringify(process.env.CONTENTFUL_TOKEN || ""),
CONTENTFUL_SPACE_ID: JSON.stringify(
process.env.CONTENTFUL_SPACE_ID || ""
),
PORT: JSON.stringify(process.env.PORT) || 3000,
},
}),
],
};
export default config;
web
, which is the browser-like environment. For the nodejs applications, use node
.__dirname
and __filename
so these two's behaviors are not changed during building.