├── assets ├── linter.png ├── set_up_five.png ├── set_up_four.png ├── set_up_nine.png ├── set_up_one.png ├── set_up_six.png ├── set_up_ten.png ├── set_up_two.png ├── linter_forced.png ├── set_up_eight.png ├── set_up_seven.png └── set_up_three.png ├── src ├── images │ └── helloworld.gif ├── fonts │ └── prototype.regular.ttf ├── index.scss └── index.jsx ├── .babelrc ├── .eslintrc.js ├── public └── index.html ├── webpack.config.js ├── package.json ├── bonus ├── image_assets_configuration.md ├── custom_font_configuration.md ├── sass_configuration.md └── eslint_configuration.md ├── .gitignore └── README.md /assets/linter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/linter.png -------------------------------------------------------------------------------- /assets/set_up_five.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_five.png -------------------------------------------------------------------------------- /assets/set_up_four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_four.png -------------------------------------------------------------------------------- /assets/set_up_nine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_nine.png -------------------------------------------------------------------------------- /assets/set_up_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_one.png -------------------------------------------------------------------------------- /assets/set_up_six.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_six.png -------------------------------------------------------------------------------- /assets/set_up_ten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_ten.png -------------------------------------------------------------------------------- /assets/set_up_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_two.png -------------------------------------------------------------------------------- /assets/linter_forced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/linter_forced.png -------------------------------------------------------------------------------- /assets/set_up_eight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_eight.png -------------------------------------------------------------------------------- /assets/set_up_seven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_seven.png -------------------------------------------------------------------------------- /assets/set_up_three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/assets/set_up_three.png -------------------------------------------------------------------------------- /src/images/helloworld.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/src/images/helloworld.gif -------------------------------------------------------------------------------- /src/fonts/prototype.regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SimplySylvia/HowTo-React-Webpack-Babel/HEAD/src/fonts/prototype.regular.ttf -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | // [presets] allow us to define the additional packages we would like to include. 3 | // This will give us access to jsx and several other newer js features. 4 | "presets": ["@babel/preset-env","@babel/preset-react"] 5 | } -------------------------------------------------------------------------------- /src/index.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Prototype Regular'; 3 | src: url('./fonts/prototype.regular.ttf') format("truetype"); 4 | font-weight: 400; 5 | font-style: normal; 6 | } 7 | 8 | body { 9 | margin: 0; 10 | padding: 0; 11 | background-color: #1f1f1f; 12 | color: #f1f1f1; 13 | } 14 | 15 | h1 { 16 | font-family: 'Prototype Regular'; 17 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | 'plugin:react/recommended', 8 | 'airbnb', 9 | ], 10 | parser: "@babel/eslint-parser", 11 | parserOptions: { 12 | ecmaFeatures: { 13 | jsx: true, 14 | }, 15 | ecmaVersion: 'latest', 16 | sourceType: 'module', 17 | }, 18 | plugins: [ 19 | 'react', 20 | ], 21 | rules: { 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // import reactDOM from "react-dom"; Version 17~ 3 | import { createRoot } from 'react-dom/client'; // version 18^ 4 | import hello from './images/helloworld.gif'; 5 | import './index.scss'; 6 | 7 | function App() { 8 | return ( 9 |
10 |

Hello World

11 | hello world animated 12 |
13 | ); 14 | } 15 | 16 | const root = createRoot(document.getElementById('root')); // version 18^ 17 | // reactDOM.render(, document.getElementById("root")); Version 17~ 18 | root.render(); // Version 18^ 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const ESLintPlugin = require('eslint-webpack-plugin'); 3 | 4 | module.exports = { 5 | mode: "development", 6 | entry: "./src/index.jsx", 7 | output: { 8 | path: path.join(__dirname, "public"), 9 | filename: "bundle.js", 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(jsx|js)$/, 15 | exclude: /node_modules/, 16 | loader: "babel-loader", 17 | }, 18 | { 19 | test: /\.s[ac]ss$/i, 20 | use: ["style-loader", "css-loader", "sass-loader"], 21 | }, 22 | { 23 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 24 | type: "asset/resource", 25 | }, 26 | { 27 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 28 | type: 'asset/resource', 29 | }, 30 | ], 31 | }, 32 | devtool: "eval-cheap-module-source-map", 33 | devServer: { 34 | static: { 35 | directory: path.join(__dirname, "public"), 36 | }, 37 | compress: true, 38 | port: 3000, 39 | }, 40 | plugins: [new ESLintPlugin()], 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react_from_scratch", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "react": "^18.0.0", 8 | "react-dom": "^18.0.0" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.17.5", 12 | "@babel/eslint-parser": "^7.17.0", 13 | "@babel/preset-env": "^7.16.11", 14 | "@babel/preset-react": "^7.16.7", 15 | "babel-loader": "^8.2.3", 16 | "css-loader": "^6.7.1", 17 | "eslint": "^8.12.0", 18 | "eslint-config-airbnb": "^19.0.4", 19 | "eslint-plugin-import": "^2.25.4", 20 | "eslint-plugin-jsx-a11y": "^6.5.1", 21 | "eslint-plugin-react": "^7.29.4", 22 | "eslint-plugin-react-hooks": "^4.4.0", 23 | "eslint-webpack-plugin": "^3.1.1", 24 | "sass": "^1.49.9", 25 | "sass-loader": "^12.6.0", 26 | "style-loader": "^3.3.1", 27 | "webpack": "^5.70.0", 28 | "webpack-cli": "^4.9.2", 29 | "webpack-dev-server": "^4.7.4" 30 | }, 31 | "scripts": { 32 | "start": "webpack --mode=development", 33 | "build": "webpack --mode=production", 34 | "dev": "webpack serve --open" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bonus/image_assets_configuration.md: -------------------------------------------------------------------------------- 1 | # ✨ Image Assets Configuration 2 | By default webpack will not allow the module import of image assets. To allow this we will include a new rule to permit this. 3 | 4 | Inside webpack.config.js: 5 | ```js 6 | module: { 7 | rules: [ 8 | { 9 | test: /\.(jsx|js)$/, 10 | exclude: /node_modules/, 11 | loader: "babel-loader", 12 | }, 13 | { 14 | test: /\.s[ac]ss$/i, 15 | use: ["style-loader", "css-loader", "sass-loader"], 16 | }, 17 | // our new rule to allow the import of image assets 18 | { 19 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 20 | type: "asset/resource", 21 | }, 22 | ], 23 | }, 24 | ``` 25 | 26 | With that set we can now import images into our files. 27 | 28 | Inside index.jsx: 29 | ```js 30 | import React from "react"; 31 | import { createRoot } from "react-dom/client"; 32 | const root = createRoot(document.getElementById("root")); 33 | 34 | import "./index.scss"; 35 | 36 | import hello from "./images/helloworld.gif"; 37 | 38 | const App = () => { 39 | return ( 40 |
41 |

Hello World

42 | hello world animated 43 |
44 | ); 45 | }; 46 | 47 | root.render(); 48 | ``` 49 | -------------------------------------------------------------------------------- /bonus/custom_font_configuration.md: -------------------------------------------------------------------------------- 1 | # ✨ Custom Font Configuration 2 | By default webpack will not allow the import of custom font types. This allow this feature we will add a new fule to our configuration. 3 | 4 | Inside webpack.config.js: 5 | ```js 6 | module: { 7 | rules: [ 8 | { 9 | test: /\.(jsx|js)$/, 10 | exclude: /node_modules/, 11 | loader: "babel-loader", 12 | }, 13 | { 14 | test: /\.s[ac]ss$/i, 15 | use: ["style-loader", "css-loader", "sass-loader"], 16 | }, 17 | { 18 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 19 | type: "asset/resource", 20 | }, 21 | // new rule to allow import of custom fonts 22 | { 23 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 24 | type: 'asset/resource', 25 | }, 26 | ], 27 | }, 28 | ``` 29 | 30 | Now that our webpack is setup we can import and create custom font faces. 31 | 32 | Inside index.css/.scss: 33 | ```css 34 | @font-face { 35 | font-family: 'Prototype Regular'; 36 | src: url('./fonts/prototype.regular.ttf') format("truetype"); 37 | font-weight: 400; 38 | font-style: normal; 39 | } 40 | 41 | body { 42 | margin: 0; 43 | padding: 0; 44 | background-color: #1f1f1f; 45 | color: #f1f1f1; 46 | } 47 | 48 | h1 { 49 | font-family: 'Prototype Regular'; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /bonus/sass_configuration.md: -------------------------------------------------------------------------------- 1 | # ✨ Sass Configuration 2 | To leverage a css preprocessor we have to include additonal dependencies and add them to our configuration. 3 | 4 | ## Sass Dependencies 5 | 6 | - [sass-loader](https://www.npmjs.com/package/sass-loader) loads a Sass/SCSS file and compiles it to CSS. 7 | - [sass](https://www.npmjs.com/package/sass) css preprocessor. 8 | 9 | ```bash 10 | yarn add sass-loader sass --dev 11 | ``` 12 | 13 | ## Sass Webpack Configuration 14 | Now that we have our dependencies installed we can tell webpack to leverge them for sass files. 15 | 16 | Inside webpack.config.js: 17 | ```js 18 | const path = require("path"); 19 | 20 | module.exports = { 21 | mode: "development", 22 | entry: "./src/index.jsx", 23 | output: { 24 | path: path.join(__dirname, 'public'), 25 | filename: "bundle.js" 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.(jsx|js)$/, 31 | exclude: /node_modules/, 32 | loader: "babel-loader" 33 | }, 34 | /* 35 | Our original css test 36 | { 37 | test: /\.css$/, 38 | use: ['style-loader','css-loader'] 39 | } 40 | */ 41 | // new css test to include sass 42 | { 43 | // looks for sass OR css files on import 44 | test: /\.s[ac]ss$/i, 45 | use: [ 46 | // Creates `style` nodes from JS strings 47 | "style-loader", 48 | // Translates CSS into CommonJS 49 | "css-loader", 50 | // Compiles Sass to CSS 51 | "sass-loader", 52 | ], 53 | }, 54 | ] 55 | }, 56 | devtool: "eval-cheap-module-source-map", 57 | devServer: { 58 | static: { 59 | directory: path.join(__dirname, 'public'), 60 | }, 61 | compress: true, 62 | port: 3000, 63 | } 64 | } 65 | ``` 66 | 67 | With this addition to our configuration we can now import sass files just like js files! 68 | 69 | Inside index.jsx: 70 | ```js 71 | import React from "react"; 72 | import { createRoot } from "react-dom/client"; 73 | const root = createRoot(document.getElementById("root")); 74 | 75 | // here is out import for our styles 76 | import "./index.scss"; 77 | 78 | const App = () => { 79 | return

Hello World

80 | } 81 | 82 | root.render(); 83 | ``` -------------------------------------------------------------------------------- /bonus/eslint_configuration.md: -------------------------------------------------------------------------------- 1 | # ✨ Eslint Configuration 2 | Eslint is a great tool to help us as developers follow a style guide and ensure a consistent code base. Our linter will run on our files and output if we are ever not following these guidelines. 3 | 4 | ## Eslint Dependencies 5 | Our core dependency will be the [eslint package](https://www.npmjs.com/package/eslint). Now there are several optional packages you can install as dependencies depending on how you want to setup the linter. We will be leveraging the built in initilizer for this. 6 | 7 | ```bash 8 | yarn add eslint --dev 9 | ``` 10 | 11 | ## Eslint Initilizer 12 | Once this has been installed we can through the setup process using the built in initilizer. 13 | 14 | ```bash 15 | yarn create @eslint/config 16 | ``` 17 | 18 | This will start an interactive prompt just like `npm init` or `yarn init`. 19 | 20 | ### Step One 21 | In this first step we are choosing how we want to use eslint. This is up to your personal use case. For this example we will choose the most demanding use case. 22 | 23 | ![choose eslint enforcement level](../assets/set_up_one.png) 24 | 25 | ### Step Two 26 | This step sets how out import statements are configured. In react we are leveraging Javascript Modules so we will select this option. 27 | 28 | ![choose import style](../assets/set_up_two.png) 29 | 30 | ### Step Three 31 | This step is the framework selection. Since we are working in react we choose react here. This will let us install the correct dependencies through this tool. 32 | 33 | ![choose framework](../assets/set_up_three.png) 34 | 35 | ### Step Four 36 | This step tells the linter if we are using typescript. For this example we are not so we will choose no. 37 | 38 | ![typescript selection](../assets/set_up_four.png) 39 | 40 | ### Step Five 41 | This step we are selection the enviroment our app will run. Since this is react a client side application we will choose browser. 42 | 43 | ![enviroment selection](../assets/set_up_five.png) 44 | 45 | ### Step Six 46 | If you want to follow a predefined style guide you can choose the use existing option OR you can go through a series of questions to define your own. For this example we will use a preexisting style guide. 47 | 48 | ![decide if you want to use a style guide](../assets/set_up_six.png) 49 | 50 | ### Step Seven 51 | In this step we can select an existing style guide based on out previous selection. Here we will use the [airbnb style guide](https://github.com/airbnb/javascript) for this example. 52 | 53 | ![choose existing style guide](../assets/set_up_seven.png) 54 | 55 | ### Step Eight 56 | This step allows us to choose how we want our configuration file to be created. For this example we use the js version. 57 | 58 | ![choose format for config file](../assets/set_up_eight.png) 59 | 60 | ### Step Nine 61 | This step allows choose if we want to install the additional dependencies to support the configurations we choose in the above steps. Here we will select yes. 62 | 63 | ![additional dependency output](../assets/set_up_nine.png) 64 | 65 | ### Step Ten 66 | Here we are finally done! Our linter has been setup and is ready to use. 67 | 68 | >NOTE: eslint config only leverages npm to install the dependencies so some clean up is manual for yarn users. 69 | Delete the `package-lock.json` and run `yarn upgrade` to update the yarn lock file. 70 | 71 | ![final output](../assets/set_up_ten.png) 72 | 73 | 74 | ### Current Directory 75 | ``` 76 | App Directory 77 | ├── package.json 78 | ├── public 79 | │ ├── bundle.js 80 | │ └── index.html 81 | ├── src 82 | │ └── index.jsx 83 | ├── .babelrc 84 | ├── .eslintrc.js <= new config file 85 | ├── webpack.config.js 86 | └── yarn.lock 87 | ``` 88 | 89 | ### Preview of linter in VsCode 90 | Our linter is now hard at work makign sure we are following the rules we set. 91 | 92 | ![preview of linter](../assets/linter.png) 93 | 94 | ## Enforce Eslint Rules 95 | Want to enforce these rules with webpack? We can do this with a little bit more setup. 96 | 97 | ### Additional Dependencies 98 | 99 | - [eslint-webpack-plugin](https://www.npmjs.com/package/eslint-webpack-plugin) to connect webpack and eslint together. 100 | - [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) to add the ability to look at our existing eslint config. 101 | 102 | ```bash 103 | yarn add eslint-webpack-plugin @babel/eslint-parser --dev 104 | ``` 105 | 106 | ### Add to webpack the new plugin. 107 | 108 | In webpack.config.js: 109 | ```js 110 | // at the top add this new import 111 | const ESLintPlugin = require('eslint-webpack-plugin'); 112 | // inside the exports add a new field labels plugins 113 | module.exports = { 114 | // ... 115 | plugins: [new ESLintPlugin()], 116 | } 117 | ``` 118 | 119 | ### Set eslint parser 120 | 121 | In .eslintrc.js: 122 | ```js 123 | module.exports = { 124 | env: { 125 | browser: true, 126 | es2021: true, 127 | }, 128 | extends: [ 129 | 'plugin:react/recommended', 130 | 'airbnb', 131 | ], 132 | // Here is our new parser option set to babel 133 | parser: "@babel/eslint-parser", 134 | parserOptions: { 135 | ecmaFeatures: { 136 | jsx: true, 137 | }, 138 | ecmaVersion: 'latest', 139 | sourceType: 'module', 140 | }, 141 | plugins: [ 142 | 'react', 143 | ], 144 | rules: { 145 | }, 146 | }; 147 | ``` 148 | 149 | And just like that now when you start up your server you will be forced to follow the rules you set in your configuration! 150 | 151 | ![example of forced rules](../assets/linter_forced.png) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HOW TO: React Setup with Webpack and Babel 2 | In this breakdown we will be going over how to setup a react development enviroment from scratch. This enviroment will include Webpack and Babel for easy development that will include hot reloading. 3 | 4 | >NOTE: This repo contains the finialized code for this setup. 5 | 6 | ## Roadmap 7 | 1. Create source 📁 directories and 📝 files. 8 | 2. Install and setup 🧶 Yarn. 9 | 3. Install ⚙️ application dependencies. 10 | 4. Set up 📦 Webpack Configuration for bundeling. 11 | 5. Set up 🪄 Babel Configuration. 12 | 6. Set up Webpack Development Server for 🔥 hot reloading. 13 | ## ✨ Additional Configurations 14 | Beyond the initial setup of the react enviroment are a variety of additonal configurations that may be helpful in an enviroment. 15 | 16 | - [Sass Configuration](/bonus/sass_configuration.md) 17 | - [Image Assets Configuration](/bonus/image_assets_configuration.md) 18 | - [Custom Font Configuration](/bonus/custom_font_configuration.md) 19 | - [Eslint Configuration](/bonus/eslint_configuration.md) 20 | 21 | ## Create source 📁 directories and 📝 files. 22 | For our application we will create some starting directories and files. 23 | 24 | Inside of your project directory: 25 | ```bash 26 | mkdir src public && touch src/index.jsx public/index.html 27 | ``` 28 | 29 | > NOTE: `src` will be the directory where we will hold all of our development code.`public` will be where our html and bundled js will go. 30 | 31 | #### Current Directory 32 | ``` 33 | App Directory 34 | ├── public 35 | │ └── index.html 36 | └── src 37 | └── index.jsx 38 | ``` 39 | 40 | We will need other files, but we will add them as we go. This would be a good time to create your .gitignore and set the default node ignores. 41 | 42 | Let's setup our base html file. 43 | 44 | Inside our index.html: 45 | ```html 46 | 47 | 48 | 49 | 50 | 51 | 52 | React App 53 | 54 | 55 | 56 |
57 | 58 | 59 | 60 | 61 | ``` 62 | 63 | > For now we will not do anything to the src/index.js. We will once we install the required dependencies for our application. 64 | 65 | ## Install and setup 🧶 Yarn. 66 | To manage our dependencies we will be using a package manager called 🧶 Yarn. You can learn more about it [here](https://yarnpkg.com/). 67 | 68 | ### Yarn Installation 69 | ```bash 70 | npm i -g yarn 71 | ``` 72 | 73 | You can verify your install using `yarn --version` and you should get back a response similiar to `1.22.17`. 74 | 75 | ### Yarn Commands 76 | 77 | | Command | Description | 78 | |----------|--------------| 79 | | yarn init | Initializes the development of a package/application. | 80 | | yarn add | Adds a package to use in your current application. | 81 | | yarn add global | Adds a package to globally available directory. | 82 | | yarn add --dev | Adds a package to your current application under the development dependencies. | 83 | | yarn install | Installs all the dependencies defined in a package.json file. | 84 | | yarn remove | Removes an unused package from your current package. | 85 | | yarn [scriptname] | Runs a script defined in the package.json | 86 | 87 | For detailed information on the commands you can check the [docs](https://classic.yarnpkg.com/en/docs/cli/). 88 | 89 | ### Yarn customization 90 | Want to turn on emojis in yarn for a more fun output? 91 | ```bash 92 | yarn config set -- --emoji true 93 | ``` 94 | There are a bunch of configurations available for yarn so check out the docs for options! 95 | 96 | ## Install ⚙️ application dependencies. 97 | Our next step is to install all the dependencies that our application and development enviroment will need. 98 | 99 | Before we can install anything we will need to initilize the directory as an node enviroment. 100 | 101 | ```bash 102 | yarn init -y 103 | ``` 104 | This command will generate a package.json with default fields. If you wish to fill out all the fields manually you can run `yarn init`. 105 | 106 | Our application is now ready for our dependencies. 107 | 108 | ### React Dependancies 109 | - [React](https://www.npmjs.com/package/react) for ui component library. 110 | - [ReactDOM](https://www.npmjs.com/package/react-dom) for connecting the ui component library to the dom. 111 | 112 | ```bash 113 | yarn add react react-dom 114 | ``` 115 | ### Webpack Dependancies 116 | 117 | - [webpack](https://www.npmjs.com/package/webpack) for bundling our code. 118 | - [webpack-cli](https://www.npmjs.com/package/webpack-cli) for terminal commands around bundling our code. 119 | - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) for hot reloading functionality. 120 | 121 | ```bash 122 | yarn add webpack webpack-cli webpack-dev-server --dev 123 | ``` 124 | >NOTE: notice the `--dev` in the above command. We are installing these are development dependencies since these are only for development purposes and will not be included in our final production version. 125 | 126 | ### Babel Dependancies 127 | 128 | - [@babel/core](https://babeljs.io/docs/en/babel-core) for translations between js versions. 129 | - [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env) for latest support of js versions along with polyfils for browser support. 130 | - [@babel/preset-react](https://babeljs.io/docs/en/babel-preset-react) for react support that includes jsx. 131 | 132 | ```bash 133 | yarn add @babel/core @babel/preset-env @babel/preset-react --dev 134 | ``` 135 | 136 | ### Loader Dependancies 137 | For hot loading with webpack-dev-server we will need to add the loaders we want to run. These are a few of the option that are available and the base options to start with. 138 | 139 | - [babel-loader](https://www.npmjs.com/package/babel-loader) to connect babel and webpack together. 140 | - [css-loader](https://www.npmjs.com/package/css-loader) to add support for css imports. 141 | - [style-loader](https://www.npmjs.com/package/style-loader) to add css injections to the dom. 142 | 143 | ```bash 144 | yarn add babel-loader css-loader style-loader --dev 145 | ``` 146 | 147 | ### Final Dependencies 148 | Our final package.json should look something like this: 149 | 150 | ```json 151 | "dependencies": { 152 | "react": "^18.0.0", 153 | "react-dom": "^18.0.0" 154 | }, 155 | "devDependencies": { 156 | "@babel/core": "^7.17.5", 157 | "@babel/preset-env": "^7.16.11", 158 | "@babel/preset-react": "^7.16.7", 159 | "babel-loader": "^8.2.3", 160 | "css-loader": "^6.7.1", 161 | "style-loader": "^3.3.1", 162 | "webpack": "^5.70.0", 163 | "webpack-cli": "^4.9.2", 164 | "webpack-dev-server": "^4.7.4" 165 | }, 166 | ``` 167 | 168 | > NOTE: Your version numbers might look different since packages update over time. 169 | 170 | #### Current Directory 171 | ``` 172 | App Directory 173 | ├── package.json 174 | ├── public 175 | │ └── index.html 176 | ├── src 177 | │ └── index.jsx 178 | └── yarn.lock 179 | ``` 180 | 181 | ## Set up 📦 Webpack Configuration for bundeling. 182 | Now it is time to setup our webpack configuration so our code can be bundled. 183 | 184 | To configure webpack we will need to create a `webpack.config.js`: 185 | 186 | ```bash 187 | touch webpack.config.js 188 | ``` 189 | 190 | #### Current Directory 191 | ``` 192 | App Directory 193 | ├── package.json 194 | ├── public 195 | │ └── index.html 196 | ├── src 197 | │ └── index.jsx 198 | ├── webpack.config.js 199 | └── yarn.lock 200 | ``` 201 | 202 | 203 | Let's setup the default settings for our webpack configuration inside the file we just created. 204 | 205 | Inside webpack.config.js: 206 | ```js 207 | // For node to know our absolute file path we will be using the internal module path 208 | const path = require("path"); 209 | 210 | // Our export here is the configuration webpack will use 211 | module.exports = { 212 | // [mode] will determine how our code will be bundled. 213 | // "development" will be human readable 214 | // "production" will be minified 215 | mode: "development", 216 | // [entry] this is the file where the bundling starts from. 217 | entry: "./src/index.jsx", 218 | // [output] is a configuration object to determine how and where to bundle our code 219 | output: { 220 | // [path] is where to output 221 | path: path.join(__dirname, 'public'), 222 | // [filename] is the name of the file 223 | filename: "bundle.js" 224 | } 225 | } 226 | ``` 227 | 228 | With this setup in place we will be able to start using the webpack terminal command to bundle out code. At the moment our index.js is empty so let's change that. 229 | 230 | > If you are using React 18^ 231 | 232 | Inside src/index.jsx: 233 | 234 | ```js 235 | // Bring React in to build a component. 236 | import React from "react"; 237 | // Import from react-dom the ability to create a root render 238 | import { createRoot } from "react-dom/client"; 239 | // create the root of the app by selection where the app should be mounted in the dom 240 | const root = createRoot(document.getElementById("root")); 241 | 242 | // Here is out base App component. 243 | // Notice we are NOT using jsx here. This is because we have not set up babel yet. 244 | const App = React.createElement("h1",null,"Hello World"); 245 | 246 | // render the root element with the provided component 247 | root.render(); 248 | 249 | ``` 250 | 251 | > If you are using React 17~ 252 | 253 | Inside src/index.jsx: 254 | ```js 255 | // Bring React in to build a component. 256 | import React from "react"; 257 | // Bring reactDOM in to mount component to the dom. 258 | import reactDOM from "react-dom"; 259 | 260 | // Here is out base App component. 261 | // Notice we are NOT using jsx here. This is because we have not set up babel yet. 262 | const App = React.createElement("h1",null,"Hello World"); 263 | 264 | // Render our app to the dom mounted to the element with id of root inside our public/index.html file. 265 | reactDOM.render(App, document.getElementById("root")); 266 | ``` 267 | > NOTE: We will be adding additional configuration to webpack as we go. 268 | 269 | To run our babel configuration let's make our life easy by adding a few scripts to our `package.json`. 270 | 271 | - `start` will tell webpack to bundle our code development. 272 | - `build` will tell webpack to bundle our code for production. 273 | 274 | Inside package.json: 275 | ```json 276 | { 277 | // ... all other fields 278 | "scripts": { 279 | "start": "webpack --mode=development", 280 | "build": "webpack --mode=production" 281 | } 282 | } 283 | ``` 284 | 285 | To run these commands all you need to do is run `yarn [command]` replacing `[command]` with the script name you want to run. 286 | 287 | ```bash 288 | yarn start 289 | ``` 290 | 291 | You should see an output from webpack bundling our code into the output file we specified in the `webpack.config.js` file we made earlier. 292 | 293 | #### Current Directory 294 | ``` 295 | App Directory 296 | ├── package.json 297 | ├── public 298 | │ ├── bundle.js 299 | │ └── index.html 300 | ├── src 301 | │ └── index.jsx 302 | ├── webpack.config.js 303 | └── yarn.lock 304 | ``` 305 | Now open your html file in the browser of your choice and we should see our `Hello World` message! 306 | 307 | 308 | > Want to learn more about webpack? Check out the [docs](https://webpack.js.org/). 309 | 310 | ## Set up 🪄 Babel Configuration. 311 | Now that webpack is set up we can configure babel to allow us to use more js features like jsx. 312 | 313 | To get started we need to create a .babelrc which is our config file. 314 | 315 | ```bash 316 | touch .babelrc 317 | ``` 318 | 319 | #### Current Directory 320 | ``` 321 | App Directory 322 | ├── package.json 323 | ├── public 324 | │ ├── bundle.js 325 | │ └── index.html 326 | ├── src 327 | │ └── index.jsx 328 | ├── .babelrc 329 | ├── webpack.config.js 330 | └── yarn.lock 331 | ``` 332 | 333 | 334 | Inside .babelrc: 335 | ```js 336 | { 337 | // [presets] allow us to define the additional packages we would like to include. 338 | // This will give us access to jsx and several other newer js features. 339 | "presets": ["@babel/preset-env","@babel/preset-react"] 340 | } 341 | ``` 342 | 343 | Now we are not quite ready to start using babel yet. We will need to configure webpack further to include it. 344 | 345 | Inside webpack.config.js: 346 | ```js 347 | const path = require("path"); 348 | 349 | module.exports = { 350 | mode: "development", 351 | entry: "./src/index.jsx", 352 | output: { 353 | path: path.join(__dirname, 'public'), 354 | filename: "bundle.js" 355 | }, 356 | // [module] will allow us to set any external modules we have added to webpack 357 | module: { 358 | // [rules] will determine the rules around those external modules 359 | rules: [ 360 | // First rule is to idenify js and jsx files and turn on babel 361 | { 362 | test: /\.(jsx|js)$/, 363 | exclude: /node_modules/, 364 | loader: "babel-loader" 365 | }, 366 | // Second rule is to check for css files and load them with the following loaders 367 | { 368 | test: /\.css$/, 369 | use: ['style-loader','css-loader'] 370 | } 371 | ] 372 | }, 373 | } 374 | ``` 375 | 376 | Now we can use all the cool js features like jsx! Time to update our application. 377 | 378 | Inside src/index.jsx: 379 | ```js 380 | import { createRoot } from "react-dom/client"; 381 | const root = createRoot(document.getElementById("root")); 382 | 383 | // Huzzah for jsx! 384 | const App = () => { 385 | return

Hello World

386 | } 387 | 388 | root.render(); 389 | ``` 390 | 391 | Go ahead and run your `start` script and check it out! 392 | 393 | > Want to learn more about Babel? Check out the [docs](https://babeljs.io/). 394 | 395 | ## Set up Webpack Development Server for 🔥 hot reloading. 396 | Now its time to speed up our development process with hot reloading. 397 | 398 | To do this we will be using the webpack-dev-server that we installed. The configuration for the server will live in the webpack configuration file. 399 | 400 | Inside webpack.config.js: 401 | ```js 402 | const path = require("path"); 403 | 404 | module.exports = { 405 | mode: "development", 406 | entry: "./src/index.jsx", 407 | output: { 408 | path: path.join(__dirname, 'public'), 409 | filename: "bundle.js" 410 | }, 411 | module: { 412 | rules: [ 413 | { 414 | test: /\.(jsx|js)$/, 415 | exclude: /node_modules/, 416 | loader: "babel-loader" 417 | }, 418 | { 419 | test: /\.css$/, 420 | use: ['style-loader','css-loader'] 421 | } 422 | ] 423 | }, 424 | // [devtool] this is an additional source map that will let the browser know what files are running our code. 425 | // Helps with error tracing. Without it we will not know where our errors are coming from because it will state that everything inside the bundle file. 426 | devtool: "eval-cheap-module-source-map", 427 | // [devServer] configuration for the live server including port 428 | devServer: { 429 | // [static] config for how what to serve 430 | static: { 431 | directory: path.join(__dirname, 'public'), 432 | }, 433 | compress: true, 434 | // [port] what port on our local machine to run the dev server 435 | port: 3000, 436 | } 437 | } 438 | ``` 439 | 440 | Now that we that we have our development server configured let's add a script to make it easy to run. 441 | 442 | Inside package.json: 443 | ```json 444 | // ... 445 | "scripts": { 446 | "start": "webpack --mode=development", 447 | "build": "webpack --mode=production", 448 | // our new script to start up our development server 449 | "dev": "webpack serve --open" 450 | }, 451 | ``` 452 | 453 | Now all we have to do to spin up our server is to run: 454 | ```bash 455 | yarn dev 456 | ``` 457 | To view your server head on over to `localhost:3000` in your browser. 458 | 459 | And just like that we are off to the races! Enjoy and.. 460 | 461 | ### Happy Hacking! 💻 --------------------------------------------------------------------------------