- Read about webpack on webpack.js.org
- Init npm project:
npm init -y
- Install webpack
npm i -D webpack webpack-cli
- Install TypeScript or Babel
npm i -D typescript ts-loader
- Add tsconfig.json
tsc --init
(read about tsconfig options here) - Create webpack.config.js webpack with ts
const path = require('path');
module.exports = {
entry: './src/index.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.[tj]s$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
};
- Configure assets
module.exports = {
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'assets/[hash][ext]',
},
module: {
rules: [
{
test: /\.(?:ico|gif|png|jpg|jpeg|svg)$/i,
type: 'asset/resource',
},
{
test: /\.(woff(2)?|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
}
- Add HtmlWebpackPlugin
npm i -D html-webpack-plugin
plugin documentation
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
title: 'Hello world',
// template: './src/index.html',
}),
]
}
- Add CSS and SASS
npm i -D css-loader sass-loader sass mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.s[ac]ss$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
],
}
- Add Clean Webpack Plugin
npm i -D clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
]
};
- Add environment variables (guide)
module.exports = (env) => ({
mode: env.development ? 'development' : 'production',
});
Also add new script to package.json: "dev": "webpack --env development"
.
12. Configure source maps (documentation)
module.exports = ({ development }) => ({
devtool: development ? 'inline-source-map' : false,
}
- Add dev server (documentation)
const devServer = (isDev) => !isDev ? {} : {
devServer: {
open: true,
hot: true,
port: 8080,
contentBase: path.join(__dirname, 'public'),
},
};
module.exports = (env) => ({
...devServer(env.development)
});
- Add Copy webpack plugin
npm i -D copy-webpack-plugin
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: 'public' },
],
}),
]
};
- Install es-lint plugin:
npm i -D eslint-webpack-plugin eslint
-
Also install es-lint plugin for typescript and air-bnb config:
npm i -D eslint-plugin-import eslint-config-airbnb-typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
-
.eslintrc:
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"airbnb-typescript/base",
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"@typescript-eslint"
]
}
- Add script to package.json:
"lint": "eslint src"
- webpack.config.js:
const ESLintPlugin = require('eslint-webpack-plugin');
const esLintPlugin = (isDev) => isDev ? [] : [ new ESLintPlugin({ extensions: ['ts', 'js'] }) ];
module.exports = ({ development }) => ({
plugins: [
...esLintPlugin(development),
]
});
- Finally, we have next webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const devServer = (isDev) => !isDev ? {} : {
devServer: {
open: true,
hot: true,
port: 8080,
contentBase: path.join(__dirname, 'public'),
},
};
const esLintPlugin = (isDev) => isDev ? [] : [ new ESLintPlugin({ extensions: ['ts', 'js'] }) ];
module.exports = ({ development }) => ({
mode: development ? 'development' : 'production',
devtool: development ? 'inline-source-map' : false,
entry: {
main: './src/index.ts',
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'assets/[hash][ext]',
},
module: {
rules: [
{
test: /\.[tj]s$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|svg)$/i,
type: 'asset/resource',
},
{
test: /\.(woff(2)?|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.s[ac]ss$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
}
],
},
plugins: [
...esLintPlugin(development),
new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
new HtmlWebpackPlugin({ title: 'Hello World' }),
new CopyPlugin({
patterns: [
{ from: 'public' },
],
}),
new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
],
resolve: {
extensions: ['.ts', '.js'],
},
...devServer(development)
});