webpack basics
In this tutorial You will learn what is webpack? How to bundle js, ts, jsx, tsx, html, css files in webpack?.
And at last we will use babel transcompiler to compile out jsx and use it in browser.
webpack
Webpack is bundler that bundles multiple js files in a single js file.
Webpack bundles only .js files, to bundle other files, we need something called
Loaders. There are many loaders available for each specific files, you check thedocswe will discuss some of the loaders for html, css, ts, tsx/jsx
add some dependencies in package.json to use webpack.
"devDependencies": { "webpack": "^5.104.1", "webpack-cli": "^6.0.1", "html-webpack-plugin": "^5.6.5", "css-loader": "^7.1.2", "style-loader": "^4.0.0", "mini-css-extract-plugin": "^2.9.4", "ts-loader": "^9.5.4", "typescript": "^5.9.3", "@babel/core": "^7.28.5", "@babel/preset-env": "^7.28.5", "@babel/preset-react": "^7.28.5", "babel-loader": "^10.0.0" }, "dependencies": { "react": "^19.2.3", "react-dom": "^19.2.3" }webpack has default configurations which can be run via
webpack --mode production. Output is thrown in./distby default.add these scripts in package.json script field:
"scripts": { "bundle:prod": "webpack --mode production --watch", "bundle:dev": "webpack --mode development --watch", }- production mode optimizes the code and --watch flag watches the change.
By Default webpack bundles code of ./src/index.js to ./dist/main.js or ./dist/bundle.js. webpack default configs can be overridden by webpack.config.js file in root.
// webpack.config.js // get a nice suggestions in .js file ↓ /** @type { import("webpack").Configuration } */ export default { // entry: "", // change if needed // output:"", // change if needed module: { rules: [ // loaders goes here ], }, plugins: [ // plugins goes here ], };
loaders
- webpack by default build only .js files. Other files like css, ts, html, needs their specific loader and plugins.
html
- webpack need a
html-webpack-plugin. It generates a html file from the bundled javascript.
import HtmlWebpackPlugin from "html-webpack-plugin";
export default {
plugins: [new HtmlWebpackPlugin()],
};
Now you can open dist/index.html file in browser (* use live-server vsc extension to auto update on file change).
- if you have your own index.html, give its path to the htmlWebpackPlugin.w
import HtmlWebpackPlugin from "html-webpack-plugin";
export default {
plugins: [new HtmlWebpackPlugin({ temeplate: "./src/index.html" })],
};
css
css is loaded by
css-loaderandstyle-loader(pnpm add css-loader style-loader -D) css-loader only generate styles from .css files whereas style-loader injects generated styles to .html .// webpack.config.js /** @type {import("webpack").Configuration} */ export default { module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"], // order should be like this ← ← ← ← // css-loader will pass output to style-loader }, ], }, };You will notice the inline styles generated by style-loader.
To extract css in a seperate main.css file, use
mini-css-extract-pluginimport MCEP from "mini-css-extract-plugin"; rules: [ { test: /\.css$/, use: [MCEP.loader, "css-loader"], // pass styles output to MCEP }, ], plugins: [new MCEP()] // register plugin and use its loader in css rulesBy default MCEP adds a main.css file in dist and link it in the index.html.
Now run dist/index.html in browser and you can see the js code being executed on browser.
ts
ts files are loaded by ts-loader
pnpm add typescript ts-loader -Dadd a very basic tsconfig.json
{ "compilerOptions": { "rootDir": "src", "outDir": "dist" }, "include": ["src/**/*"] }use ts-loader for ts files in webpack.config.js
rules: [ { test: /\.ts$/, use: ["ts-loader"], }, ];you are ready to import ts files in js. and webpack will bundle it via ts-loader
import { Web } from "./web.ts"But this is a very odd way to import files, Usually we don't use extensions to import
import { Web } from "./web". This throws error becoz webpack does not know if it is a ts or css or any other file.Webpack tries to resolve ./web.js which is not available
Solution: Tell webpack if a file extension is not given, automatically resolve it to .ts
//webpack.config.js
export default {
module: { rules: [ ... ], },
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"], // you can add multiple extension resolvers
},
plugins: [...],
};
import { Web } from "./web"resolves to → ./web.js, ./web.jsx, ./web.ts, ./web.tsx
jsx or React
like other loaders we need a tsx or jsx loader like babel-loader.
Babel is a transcompiler which compiles js source code to another js code which makes it compatible with other older browser versions.
use @babel/preset-react to convert jsx → js
pnpm add @babel/core @babel/preset-react babel-loader -D// add to rules { test: /\.jsx$/, use:{ loader: "babel-loader", options: { presets: ["@babel/preset-react"], // to compile .jsx | .tsx files it need @babel/preset-react }, }, }Now webpack will successfully compile jsx into js and dist/index.html can be load on browser
But still you will see nothing on browser or may be in browser console you will see error: React not found.
- @babel/preset-react converts jsx to js in following way:
// src/index.jsx
function App() {
return (
<div className="app">
<div className="message">Welcome to App</div>
<div>Hello World</div>
</div>
);
}
// ↓ converts to somewhat like
// dist/bundle.js
React.createElement(
"div",
{ className: "app" },
React.createElement("div", { className: "message" }, "Welcome to App"),
React.createElement("div", null, "Hello World")
);
// *you can confirm by searching the funcition Name in dist/bundle.js
when this
React.createElementcode reaches browser, React is not able to resolve, as there are no node_modules in browser.Hence even if webpack bundled code correctly, but in runtime browser is unable to resolve the code.
Solution: make runtime automatic in babel react preset → It imports react package in the bundled js instead of relying on node_modules.
// webpack.config.js
presets: [
//"@babel/preset-react" → invalid
["@babel/preset-react", { runtime: "automatic" }],
];
Now check the dist/bundle.js you will not find any direct React function call.
This solves the error and make react code ready to run on browser as usual.