Sådan oprettes en React-app fra bunden ved hjælp af Webpack 4

I de sidste tre uger har jeg forsøgt at oprette en React-app fra bunden for at forstå opsætningen med Webpack. Mit mål var at oprette en simpel konfiguration, som derefter kan dyrkes videre. Det har været en kamp for at forstå Webpack. Men takket være denne tutorial af Valentino Gagliardi er jeg meget oplyst.

Hvad jeg planlægger at gøre er at lave en søgefunktionalitet med falske JSON-data (eller ægte). I dette blogindlæg vil jeg gennemgå opsætningen af ​​mit projekt. I den næste planlægger jeg at vise, hvordan jeg konfigurerer test. Jeg vil også gerne tilføje en server til dette ved hjælp af Node.js, men er ikke sikker på, om omfanget af mit projekt ville have brug for det.

( Bemærk : Jeg har leveret min Webpack-opsætning i slutningen af ​​dette blogindlæg)

Uden yderligere ado, lad os fortsætte med opsætningen!

Lav et nyt projekt og cd til det:

mkdir react_searchcd react_search

Opret en package.json- fil:

npm init

Hvis du vil springe alle spørgsmål over, skal du tilføje -y-flagget:

npm init -y

Vi har brug for at installere webpack som en dev-afhængighed og webpack-cli, så du kan bruge webpack i kommandolinjen:

npm i webpack webpack-cli -D
  • i: installer
  • -D: - gem-dev

Opret en src-mappe med index.js og placer følgende kode som et eksempel:

console.log("hello");

Tilføj nu følgende scripts til din package.json (i fed skrift):

{ "name": "react_search", "version": "1.0.0", "description": "Search app using React", "main": "index.js", "scripts": { "start": "webpack --mode development", "build": "webpack --mode production" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.0.1", "webpack-cli": "^2.0.10" } }

Webpack 4 har nu to tilstande, udvikling og produktion, hvor kode minimeres i sidstnævnte.

Se det selv ved at løbe:

npm run start

Dette opretter en dist- mappe med main.js- fil indeni (indeholdende din src-kode).

Hvis du nu løber:

npm run build

Følgende output er nu sådan:

Opsætning af React og Babel

For at arbejde med React skal vi installere det sammen med Babel. Dette transpilerer koden fra ES6 til ES5, da ikke alle browsere understøtter ES6 endnu (for eksempel Internet Explorer).

Installer react og react-dom som en afhængighed

npm i react react-dom -S
  • -S: - gem

Installer derefter babel-core , babel-loader , babel-preset-env og babel-preset-react som en dev-afhængighed:

npm i babel-core babel-loader babel-preset-env babel-preset-react -D
  • babel-core : Transformerer din ES6-kode til ES5
  • babel-loader : Webpack-hjælper til at omdanne dine JavaScript-afhængigheder (for eksempel når du importerer dine komponenter til andre komponenter) med Babel
  • babel-preset-env : Bestemmer, hvilke transformationer / plugins der skal bruges, og polyfills (giver moderne funktionalitet på ældre browsere, der ikke understøtter det oprindeligt) baseret på den browsermatrix, du vil understøtte
  • babel-preset-react : Babel preset for alle React-plugins, for eksempel at gøre JSX til funktioner

Vi er nødt til at oprette en webpack.config.js- fil for at angive reglerne for vores babel-loader.

module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] } };

Vi skal derefter oprette en separat fil kaldet .babelrc for at give mulighederne for babel-loader. Du kan medtage det i filen webpack.config.js, men jeg har set, at de fleste projekter har dette adskilt. Dette resulterer i klarere læsbarhed, og det kan bruges af andre værktøjer, der ikke er relateret til webpack. Når du angiver, at du bruger babel-loader i din webpack-konfiguration, vil den se efter .babelrc-filen, hvis der er en.

{ "presets": ["env", "react"] }

Dernæst skal du ændre din index.js- fil for at gengive en komponent:

import React from "react"; import ReactDOM from "react-dom"; const Index = () => { return Hello React! ; }; ReactDOM.render(, document.getElementById("index"));

Vi bliver også nødt til at oprette en index.html- fil i src- mappen, hvor vi kan tilføje vores sektionselement med id index. Det er her, vi gengiver vores vigtigste reaktionskomponent:

      React and Webpack4     

Nu skal vi installere html-webpack-plugin og bruge dette i vores webpack-konfigurationsfil. Dette plugin genererer en HTML-fil med injiceret, skriver th er til dist / index .html og minifiserer filen.

Installer html-webpack-plugin som en dev-afhængighed:

npm i html-webpack-plugin -D

Opdater webpack-konfigurationen sådan:

const HtmlWebPackPlugin = require("html-webpack-plugin"); const htmlPlugin = new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }); module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }, plugins: [htmlPlugin] };

Du kan også indtaste pluginet sådan:

plugins: [ new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }); ]

Men jeg foretrækker at udtrække dette til en variabel, så jeg kan se listen over plugins, jeg bruger.

Den værdi, jeg giver templatenøglen, er hvor jeg leder efter min HTML-fil. Filnavnværdien er navnet på den minificerede HTML, der genereres i dist-mappen.

Hvis du nu kører, skal npm run startdu se index.html genereres i dist-mappen.

Run open dist/index.html and you should see “Hello React” in your browser.

Setting up webpack-dev-server

It is a bit tedious to keep running this command every time you want to see your changes in the browser. To have webpack “watch” our changes and thus refresh whenever we have made changes to any of our components, we can use webpack-dev-server module.

Go ahead and install this as a dev dependency

npm i webpack-dev-server -D

Then change your package.json start scripts like so (in bold):

{ "name": "react_search", "version": "1.0.0", "description": "Search app using React", "main": "index.js", "scripts": { "start": "webpack-dev-server --mode development --open", "build": "webpack --mode production" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "react": "^16.2.0", "react-dom": "^16.2.0" "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.4", "babel-preset-env": "^1.6.1", "babel-preset-react": "^6.24.1", "html-webpack-plugin": "^3.0.6", "webpack": "^4.1.1", "webpack-cli": "^2.0.10", "webpack-dev-server": "^3.1.0" } }

If you now run npm run start you should see localhost:8080 open up in your default browser — that’s what the —-open flag is for. Now everytime you make changes, it will refresh the page.

You can also add a --hot flag to your npm start script which will allow you to only reload the component that you’ve changed instead of doing a full page reload. This is Hot Module Replacement.

Setting up CSS

The last part involves setting up our CSS. As we will be importing CSS files into our React components, we need css-loader module to resolve them. Once that’s resolved, we also need a style-loader to inject this into our DOM — adding a tag into the element of our HTML.

Go ahead and install both of these modules as a dev dependency:

npm i css-loader style-loader -D

We then need to update our webpack.config.js file like so:

const HtmlWebPackPlugin = require("html-webpack-plugin"); const htmlWebpackPlugin = new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }); module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.css$/, use: ["style-loader", "css-loader"] } ] }, plugins: [htmlWebpackPlugin] };

Note that the order of adding these loaders is important. First, we need to resolve the CSS files before adding them to the DOM with the style-loader. By default, webpack uses the loaders from the right (last element in the array) to the left (first element in the array).

Making CSS modular

We can also make CSS modular using webpack. This means class name will be scoped locally and specific to only the component in question.

To do this, we can provide some options to css-loader:

const HtmlWebPackPlugin = require("html-webpack-plugin"); const htmlWebpackPlugin = new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }); module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader", options: { modules: true, importLoaders: 1, localIdentName: "[name]_[local]_[hash:base64]", sourceMap: true, minimize: true } } ] } ] }, plugins: [htmlWebpackPlugin] };

As we need to give options, each loader is now an object with a key-value pair. To enable CSS modules, we need to set module option for css-loader to be true. The importLoaders option configures how many loaders before css-loader should be applied. For example, sass-loader would have to come before css-loader.

The localIdentName allows you to configure the generated identification.

  • [name] will take the name of your component
  • [local] is the name of your class/id
  • [hash:base64] is the randomly generated hash which will be unique in every component’s CSS

To make this a bit more visual, I’ll give you an example. Say I have a component named Form and I have a button with a CSS class primaryButton. I also have another component called Search and a button in it with a CSS class primaryButton. However, both of these classes have different CSS:

Form button.primaryButton { background-color: green; } Search button.primaryButton { background-color: blue; }

When webpack bundles your application, depending on which CSS comes latest, both of your buttons could have the color green or blue instead of Form having green and Search having blue.

This is where the localIdentName comes into place. With this, once your application is bundled, your buttons will have a unique class name!

As you can see, the button class name in the Form component is different to the one in the Search component — their naming starts with the name of the component, class name, and unique hash code.

So with this, you won’t have to worry about whether you have given the same class name throughout your whole application — you only have to worry about whether you have used it in the same component.

This concludes the first part of setting a React app from scratch. In the next blog post, I aim to explain how to set up tests for TDD and how to write them.

Please let me know if something is unclear and I’ll explain the best as I can. I value and welcome constructive feedback as this helps me to improve :)

Hope this helps!

EDIT

Importing CSS

I’ve had a few comments asking me how they can render CSS which I didn’t touch on previously. What you need to do is import the CSS file in your React component. For example, say you have a Search component and this is your tree directory:

You will need to import your CSS file in your Search component like so:

import style from "./Search.css"

Du kan derefter anvende forskellige CSS-klassestilarter såsom:

const Search = () => { return Hello Search Component :) }

Du behøver ikke at kalde det stil, men hvad jeg fandt er, at de fleste mennesker har givet det dette navn i deres projekter.

Min Webpack kedelplade

For alle, der ønsker en hurtig klon af denne Webpack-opsætning, har jeg dette på min GitHub. Jeg har også inkluderet en mere kortfattet guide i README.

Indgangs- og udgangspunkter

Webpack 4 har som standard et standardindgangspunkt for index.js i din src- mappe. Hvis du vil pege på en anden fil, kan du gøre det ved at angive et indgangspunkt i din webpack-konfigurationsfil:

f.eks

module.exports = { entry: "./src/app.js", module: { ... } }

Du kan også angive outputfil som sådan:

const path = require('path') module.exports = { entry: "./src/app.js", output: { path: path.resolve(‘dist’), filename: ‘bundled.js’ }, module: { ... } }

Tak til Gudu Kassa for at påpege dette!

Hvis du har fundet dette nyttigt, så del det på sociale medier :)

www.pinglinh.com

Følg mig på Twitter Tjek min LinkedIn | Se min GitHub