const {resolve} = require("path");
module.exports = {
entry: resolve(process.cwd(), "src", "index.js"),
output: {
path: resolve(process.cwd(), "dist"),
filename: "main.js",
},
};
Possible modes are:
webpack --mode development
// webpack.config.js
module.exports = {
mode: "development",
};
How to use TypeScript in your webpack config:
webpack.config.js
to
webpack.config.ts
.
@types/webpack
and
ts-node
.
webpack.Configuration
type.
import webpack from "webpack";
const config: webpack.Configuration = {
// ...
};
export default config;
{
"compilerOptions": {
"esModuleInterop": true
}
}
How does it work?
ts-node
needs to be available in your
node_modules
.
This means that you can also use
Babel
to precompile your
webpack.config.js
.
Rename it to
webpack.config.babel.js
and make sure
that there is also a Babel config in your project
directory.
module.exports = () => {
return {
mode: "development",
};
};
webpack --env.mode=production --env.debug
module.exports = (env) => {
};
module.exports = (env = {}) => {
};
module.exports = (env = {}) => {
const {
mode,
debug,
} = env;
};
module.exports = (env = {}) => {
const {
mode = "development",
debug = false,
} = env;
};
module.exports = (env = {}) => {
const {
mode = "development",
debug = false,
} = env;
return {
mode,
output: { pathinfo: debug === true },
};
};
This feature is called Environment Options.
module.exports = [
{
name: "web",
target: "web",
output: { path: resolve(__dirname, "dist", "web") },
},
{
name: "node",
target: "node",
output: { path: resolve(__dirname, "dist", "node") },
},
];
In multi-compiler mode webpack builds each config concurrently in the same process while re-using the file system cache.
Multi-compiler mode does not execute each build in parallel.
module.exports = async () => {
// load some config values from database
return {
// ...
};
};
Question: Is the following config valid?
module.exports = {
entry: async () => loadEntriesFromDb(),
};
Answer: Yes, it's valid! πππ
module.exports = {
entry: async () => loadEntriesFromDb(),
};
Question: Is the following config valid?
module.exports = {
output: {
path: fs.createWriteStream("/some/path"),
},
};
webpack --watch
nodemon --exec "webpack --watch"
nodemon --watch webpack.config.js --exec "webpack --watch"
Only watch config files!
require.resolve()
module.exports = {
resolve: {
alias: {
"/does/not/exist.js": "./src/replaced.js",
},
},
};
module.exports = {
resolve: {
alias: {
[require.resolve("./src/index.js")]:
require.resolve("./src/replaced.js"),
},
},
};
.filter(Boolean)
module.exports = {
module: {
rules: [
{
test: /\.css$/,
loader: "style-loader",
},
],
},
};
module.exports = {
module: {
rules: [
isDev && {
test: /\.css$/,
loader: "style-loader",
},
].filter(Boolean),
},
};
[ ... ].filter(Boolean)
removes all falsy values from an array.
module.exports = {
plugins: [
analyze && new BundleAnalyzerPlugin(),
].filter(Boolean),
};
const rules = [];
const plugins = [];
if (isDev) {
rules.unshift({
test: /\.css$/,
loader: "style-loader",
});
}
if (analyze) {
plugins.push(new BundleAnalyzerPlugin());
}
module.exports = {
module: {
rules,
},
plugins
};
module.exports = {
module: {
rules: [
isDev && {
test: /\.css$/,
loader: "style-loader",
},
].filter(Boolean),
},
plugins: [
analyze && new BundleAnalyzerPlugin(),
].filter(Boolean),
};
const webpackMerge = require("webpack-merge");
const devConfig = {
module: {
rules: [{
test: /\.css$/,
loader: "style-loader",
}]
}
};
module.exports = webpackMerge(
{ /* base config */ },
mode === "development" ? devConfig : prodConfig
);
module.rules[].oneOf
.module.rules[].oneOf
option do? π€
Three important things to remember about loaders:
Given this rules
config, what loaders will be executed on a .js
module and in which order?
rules: [{
use: ["a-loader", "b-loader"],
}, {
use: ["c-loader"],
}],
Answer: 3.
Remember: From bottom to top and from right to left.
rules: [{
use: ["a-loader", "b-loader"],
}, {
use: ["c-loader"],
}],
c-loader
β
b-loader
β
a-loader
rules: [{
oneOf: [{
use: ["a-loader", "b-loader"],
}, {
use: ["c-loader"],
}],
}],
Now the answer is:
b-loader
β
a-loader
test
for file extensions, include
for absolute paths.rules: [{
include: [path.resolve(__dirname, "src")],
use: ["ts-loader"],
}],
rules: [{
include: [path.resolve(__dirname, "src")],
exclude: [/node_modules/],
use: ["ts-loader"],
}],
rules: [{
include: [path.resolve(__dirname, "src")],
exclude: [/node_modules/],
test: [/\.ts$/, /\.tsx$/],
use: ["ts-loader"],
}],
rules: [{
include: [path.resolve(__dirname, "src")],
exclude: [/node_modules/],
test: [/\.ts$/, /\.tsx$/],
resource: [path.resolve(__dirname, "src")],
use: ["ts-loader"],
}],
rules: [{
test: [/\.ts$/, /\.tsx$/],
use: ["ts-loader"],
}],
test
for file extensionsinclude
for directories and absolute pathsrules: [{
include: [path.resolve(__dirname, "src")],
test: [/\.ts$/, /\.tsx$/],
use: ["ts-loader"],
}],
test
for file extensionsinclude
for directories and absolute paths
Pro tip π: always use include
rules: [{
include: [
path.resolve(__dirname, "src"),
],
test: /\.js$/,
use: ["babel-loader"],
}],
rules: [{
include: [
path.resolve(__dirname, "src"),
path.resolve(__dirname, "node_modules", "modern-module"),
],
test: /\.js$/,
use: ["babel-loader"],
}],
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
export default () => (
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
);
import CircleComponent from "./circle.svg";
const component = <CircleComponent />;
body {
background: url("./circle.svg");
}
Should webpack transform the module with the react-svg-loader or with the file-loader π€?
Solution #1
import CircleComponent from "./circle.svg?component";
const component = <CircleComponent />;
rules: [{
oneOf: [{
test: /\.svg$/,
resourceQuery: "?component",
use: ["react-svg-loader"],
}, {
test: /\.svg$/,
use: ["file-loader"],
}]
}],
Solution #2
rules: [{
test: /\.svg$/,
issuer: /\.jsx$/,
use: ["react-svg-loader"],
},
{
test: /\.svg$/,
issuer: /\.css$/,
use: ["file-loader"],
}],
import CircleComponent from "./circle.svg";
const component = <CircleComponent />;
body {
background: url("./circle.svg");
}
require.resolve()
.filter(Boolean)
module.rules[].oneOf
test
for file extensions, include
for absolute paths
resourceQuery
condition
issuer
condition