After using creat-React-app a lot, I was curious about this, so I went to touch webPack and implemented a react scaffolding myself.
I built a simple React scaffolding in Windows operating system. It supports TypeScript and can deal with static resources such as CSS, images and iconfont. I realized tree-shaking and compression of CSS. Split the development and production environments and installed some additional plug-ins to optimize the development experience.
I would be grateful if someone could point out some areas that could be improved
First, environmental preparation
1, environmental
- windows
- node
- vscode
- git
2. Project initialization
Start by creating a project folder and entering the following commands on the command line
NPM install webpack webpack NPM install webpack-cli -D/ / for webpack version5.14.0
New-Item webpack.config.js -typeThe file / / create'webpack.config.js'This file creates the SRC folder where the packaged entry TS files will be storedstart
mkdir src
cd src
New-Item index.ts -type file
cd. // Create a SRC folder to store the packaged entry ts filesend
Copy the code
Now, the project structure is as follows:
.├ ── ├─ SRC │ ├─ ├─ package-lock.json ├─ download.config.jsCopy the code
3. Run the NPM build command
Add the following code to package.json
"scripts": {
"build": "webpack"
}
Copy the code
This will be packaged when NPM run build is run.
4. Configure the webPack entry and exit
Copy the following code into webpack.config.js
// webpack.config.js
const path = require('path');
module.exports = {
entry: {
app: './src/index.ts'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',}}Copy the code
!!!!!!!!! Note that Webpack is only responsible for packing files into the dist directory. If there are files in the dist directory, the files with the same name will be overwritten and the files with different names will not be deleted.
5. Configure the HTML to inject for Dist packaged by WebPack
① Installing plug-ins
// WebPack5 is installed like this, with @next more than Webpack4
npm i --save-dev html-webpack-plugin@next
Copy the code
② Use plug-ins
// webpack.config.js
// Add the first line
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {---- here is the other code ----// Add the second line
plugins: [new HtmlWebpackPlugin({
title: 'webpack is funny'.template: path.resolve(__dirname, './public/index.html'),
filename: 'index.html'})]};Copy the code
The HtmlWebpackPlugin will automatically exchally inject the dist index.ts into the public index. HTML. Title is a custom variable that can be passed.
③ Customize the HTML template
Create a new public folder under the root directory and create a new index.html folder inside.
Now, suppose I created the following HTML template:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Copy the code
This completes the configuration of the HTML that webPack’s dist will inject
6, test,
Enter the following in index.ts
var root = document.getElementById("root");
root.innerHTML = "hello world";
Copy the code
Run NPM run build and a dist folder appears in the first line of the directory
Open index. HTML under Dist in your browser and hello World appears, indicating successful initialization
Introduce TypeScript
To use TypeScript, install TypeScript;
In order for WebPack to escape TypeScript to ES5 at packaging time, ts-Loader needs to be installed and configured.
Install TypeScript and TS-Loader
npm install typescript ts-loader --save-dev
Copy the code
Configure TypeScript and TS-Loader
1) TypeScript configuration
Create a new tsconfig folder in the root directory, write nothing, and the default configuration is automatically adopted.
// Write nothing
Copy the code
(2) ts – loader is used
module.exports = {
// Add the first piece of code start
resolve: {
extensions: ["".".webpack.js".".web.js".".ts".".tsx".".js"],},// Add the first paragraph end
module: {
rules: [{test: /\.tsx? $/, loader: "ts-loader".exclude: /node_modules/ },// Add the second piece of code]}}Copy the code
3, test,
Change the contents of index.ts to the following:
let a: string = "hello world";
var root = document.getElementById("root");
root.innerHTML = a;
Copy the code
Run NPM run build and print Hello World again
React
1, install,
npm install react react-dom @types/react @types/react-dom
Copy the code
2. Configure tsconfig.json
Add the following to tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true.// indicates support for import syntax
"jsx": "react".// Indicate that react is used
"sourceMap": true}}Copy the code
3, test,
TSX: this is the react code for ts.
Then modify index.tsx to the following code
import React from "react";
import ReactDom from "react-dom";
interface HelloProps {
compiler: string;
framework: string;
}
class App extends React.Component<HelloProps> {
render() {
return (
<>
<div className="app-text">
{this.props.compiler} and {this.props.framework}!
</div>
</>
);
}
}
ReactDom.render(
<App compiler="TypeScript" framework="React" />.document.getElementById("root"));Copy the code
Run NPM run build and open dist index. HTML. If the following message is displayed, the React injection is successful.
4. Introduce CSS
Want to pack the CSS file, need to use style – loader/MiniCssExtractPlugin. Loader, CSS – loader pretreatment CSS files.
CSS – loader parsing CSS import, style – loader/MiniCssExtractPlugin. Alternative loader, if use MiniCssExtractPlugin MiniCssExtractPlugin loader and installation.
Style – loader and MiniCssExtractPlugin. The style is the difference between a loader – loader is CSS into the DOM, and MiniCssExtractPlugin. Loader is CSS individually packaged in a CSS file.
1, install,
npm install --save--dev style-loader css-loader mini-css-extract-plugin
Copy the code
2, use,
You can do it one of two ways
// If you want CSS to be injected into DOM
module: {
rules: [{test: /\.css$/i,
use: ["style-loader"."css-loader"],},],}Copy the code
// To extract CSS
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [{test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],},],},plugins: [new MiniCssExtractPlugin({
filename: "css/[name].css".// Here is a custom output filename})]};Copy the code
3, test,
First, create an index. CSS in the SRC directory and type the following
.app-text {
color: red;
background: skyblue;
height: 100px;
}
Copy the code
In index. TSX, we already have an app-text div, so we just import it
// index.css
import './index.css'
Copy the code
Now run NPM run build and open the index.html in dist directory. The following words and styles appear in the browser, indicating that CSS is successfully introduced
5. Introduce pictures
To package images, use file-loader or url-loader.
The file-loader will print the image as a separate file, and the URl-loader will package the image into an HTML embedded image.
1, install,
npm install url-loader file-loader --save-dev
Copy the code
2, use,
The configuration for packing images is as follows:
It looks like it will use url-loader instead of file-loader to package images. The default file-loader configuration is used when the image is larger than 8192, and the image is packaged separately. OutputPath indicates that images will be placed in the IMGS directory when file-loader is used.
rules: [
{
test: /\.(png|jpg|gif|svg|jpeg|bmp|tiff)$/i,
use: [
{
loader: 'url-loader'.options: {
limit: 8192.outputPath: "imgs",},},],},Copy the code
In order to import images in index. TSX (TypeScript doesn’t recognize images), we also need to define an images.d.ts folder in the root directory and type the following
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
Copy the code
3, test,
Add two lines of code under index.tsx
import Bear from ".. /public/imgs/bear.jpg"; / / to add
<div className="app-text">
<img src={Bear} />{this.props.compiler} and {this.props. Framework}!</div>
Copy the code
Run NPM run build, an IMGS folder appears in dist directory, open the index
Use iconfont
1. Download IconFont
www.iconfont.cn/
2. Create a Fonts folder
Create a fonts folder under the public, in the downloaded. CSS. | eto |. SVG |. The vera.ttf | woff five files (of course also can all into the, other useless file webpack does not ignore)
3. Modify iconfont. CSS
Eot is one of the first iconfont urls to add a “./” to all iconfont urls.
If you want to use iconfont instead of using pseudo-classes, simply remove the pseudo-class code from iconfont. CSS to reduce the size of the file. The magnifying glass below, I deleted it.
// Delete all :before elements without using the pseudo-class method. Iconfangdajing :before {content:"\e614";
}
Copy the code
4. Configure WebPack
//webpack.config.js
rules: [{test: /\.(woff|woff2|eot|ttf|otf|)$/,
loader: "file-loader".options: {
name: "[name].[ext]".outputPath: "fonts",}},],Copy the code
If the import CSS using MiniCssExtractPlugin loader, then provide the its options. PublicPath; If the style-loader is used, no modification is required.
rules: [
{
test: /\.css$/i,
use: [
//"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /",}},"css-loader",]}],Copy the code
5, test,
Add iconfont. CSS to index. CSS
@import ".. /public/fonts/iconfont.css";
Copy the code
Use iconfont in index.tsx
render() {
return (
<>
<div className="app-text">
<img src={Bear} />
{this.props.compiler} and {this.props.framework}!
</div>
<span className="iconfont"></span>// This line is added</>
);
}
Copy the code
Run NPM run build and open index.html in dist directory. The following situation indicates that iconfont is used successfully
7. Delete Dist before packaging
Use a clean-Webpack-plugin
1, install,
npm install --save-dev clean-webpack-plugin
Copy the code
2, use,
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin(),
],
Copy the code
Don’t test the
Optimize command line prompt
1, install,
npm install friendly-errors-webpack-plugin --save-dev
Copy the code
2, use,
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
plugins: [
new FriendlyErrorsWebpackPlugin(),
],
Copy the code
Don’t test the
Support the latest syntax of CSS
Like animation, 3D, things like that
1, install,
npm install --save-dev postcss-loader postcss postcss-preset-env
Copy the code
2, use,
In webpack. Config. Js
rules: [
{
test: /\.css$/i,
use: [
// "style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /",}},"css-loader"."postcss-loader".// Add the line of code],},],Copy the code
Create a new file postcss.config.js in the root directory
module.exports = {
plugins: [["postcss-preset-env",
{
// Options},]],};Copy the code
3, test postCSS-PRESET -env with CSS animation
I resized the image in index.css and defined an animation for it
// index.css
@keyframes move {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(1000px); }}img {
width: 100px;
height: 100px;
animation-name: move;
animation-duration: 2s;
}
Copy the code
After running the NPM run build, the CSS file under Dist looks like this, probably using the default configuration to enable the browser to support some advanced features
@-webkit-keyframes move {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(1000px); }}@keyframes move {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(1000px); }}img {
width: 100px;
height: 100px;
-webkit-animation-name: move;
animation-name: move;
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
Copy the code
When I open index.html, I see the bear image moving slowly from the left to the right, and then back to where it came from
Eliminate unused CSS
1. Install purgecss-webpack-plugin
npm install purgecss-webpack-plugin --save-dev
Copy the code
2, use,
Use of purgecss-webpack-plugin with mini-CSs-extract-pluigin (installed)
const glob = require('glob')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const PATHS = {
src: path.join(__dirname, 'src')}module.exports = {
module: {
rules: [{test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"]]}},plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",}).new PurgeCSSPlugin({
paths: glob.sync(`${srcPath}/ * * / * `, { nodir: true}})}),]Copy the code
3, test,
Add two lines to SRC’s index.css
The result is that the CSS file under DIST removes this code
Compress CSS code
1, install,
npm install --save-dev optimize-css-assets-webpack-plugin
Copy the code
2, use,
var OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
plugins: [
new OptimizeCssAssetsWebpackPlugin(),
],
Copy the code
The packed CSS is then compressed into a single line
The separation of development environment and production environment
1. Split files first
Enter the following on the command line
mkdir webpack-config
cd webpack-config
New-Item webpack.common.js -type file
New-Item webpack.dev.js -type file
New-Item webpack.prod.js -type file
New-Item paths.js -type file
cd.Copy the code
Configure commands in package.json
"scripts": {
"build": "webpack --config webpack-config/webpack.prod.js"."dev": "webpack serve --config webpack-config/webpack.dev.js"
},
Copy the code
2. Install webpack-dev-server to implement HMR
HMR can be implemented in listener mode, webpack-dev-server, and webpack-dev-middleware. I chose Webpack-dev-server
npm install webpack-dev-server --save--dev
Copy the code
3. Split code
1) paths. Js
const path = require("path");
const srcPath = path.join(__dirname, ".."."src");
const distPath = path.join(__dirname, ".."."dist");
const publicPath = path.join(__dirname, ".."."public");
module.exports = {
srcPath,
distPath,
publicPath,
};
Copy the code
(2) webpack.com mon. Js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
const { srcPath, publicPath } = require("./paths");
const glob = require("glob");
const PurgeCSSPlugin = require("purgecss-webpack-plugin");
module.exports = {
entry: path.join(srcPath, "index.tsx"),
module: {
rules: [{test: /\.tsx? $/, loader: "ts-loader".exclude: /node_modules/ },
{
test: /\.css$/i,
use: [
// "style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /",}},"css-loader"."postcss-loader",]}, {test: /\.(woff|woff2|eot|ttf|otf|)$/,
loader: "file-loader".options: {
name: "[name].[ext]".outputPath: "fonts",},},],},plugins: [
new HtmlWebpackPlugin({
title: "webpack is funny".template: path.join(publicPath, "index.html"),
filename: "index.html",}).new MiniCssExtractPlugin({
filename: "css/[name].css",}).new PurgeCSSPlugin({
paths: glob.sync(`${srcPath}/ * * / * `, { nodir: true})}),new OptimizeCssAssetsWebpackPlugin(),
],
};
Copy the code
(3) webpack. Dev. Js
const webpackCommonConf = require("./webpack.common.js");
const merge = require("webpack-merge");
const { distPath } = require("./paths");
var FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin");
module.exports = merge(webpackCommonConf, {
devtool: "inline-source-map".module: "development".module: {
rules: [
// Import the image URL directly
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
use: "file-loader",}]},devServer: {
historyApiFallback: true.contentBase: distPath,
open: true.hot: true.quiet: true.port: 8082,},plugins: [new FriendlyErrorsWebpackPlugin()],
});
Copy the code
(4) webpack. Prod. Js
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const webpackCommonConf = require("./webpack.common.js");
const merge = require("webpack-merge");
const { distPath } = require("./paths");
module.exports = merge(webpackCommonConf, {
mode: "production".output: {
filename: "bundle.[contentHash:8].js".// When wrapping code, add a hash stamp
path: distPath,
},
module: {
rules: [{test: /\.(png|jpg|gif|svg|)$/i,
use: [
{
loader: "url-loader".options: {
limit: 8192.outputPath: "imgs",},},],},plugins: [new CleanWebpackPlugin()],
});
Copy the code
Then the webpack.config.js file in the root directory can be deleted
NPM Run Dev or NPM Run Build can then use the development and production environments respectively
13, styled – components
Webpack is packaged with default styles that are global, and there are many solutions in the community to introduce local styles. Personally, styled components is preferred.
1, install,
npm install --save styled-components
Copy the code
2, configuration,
Add the following code to package.json
{
"resolutions": {
"styled-components": "^ 5"}}Copy the code
3, use,
① Add local styles
import styled from "styled-components";
const Container = styled.div` width: 100vw; height: auto; `; <Container> this is a styled div<Container>Copy the code
Styled -components How to use:
www.jianshu.com/p/20215e035…
zhuanlan.zhihu.com/p/29344146
② Add global styles
/ / global CSS
import { createGlobalStyle } from "styled-components";
export const Globalstyle = createGlobalStyle'Your CSS code'
// Inject a global style into index.tsx
const App = () = > {
return (
<>
<Globalstyle />
</>
);
};
Copy the code
Xiv. Summary
The basic function
- Introducing the TypeScript
- The introduction of the React
- The introduction of CSS
- Introduction of pictures
- The introduction of iconfont
- Supports the latest CSS features
All the above functions are implemented by Loader
The CSS in JS scheme is styled- Components
Development experience
- Remove dist — a plug-in before packaging
- Optimize command line prompt – a plug-in
- Distinguish between production and development environments
Optimizing production
- Small images are inlined and large images are packaged – two Loaders and a plugin
- Eliminate unused CSS – tree-shaking
- Compressing CSS code – a plug-in
- Use contentHash — long cache