React With Webpack (5)

This is a webpack 4 frontend architecture series focused on building a frontend scaffold from scratch. It shows how to combine popular modern technologies—React, Redux, webpack 4, and related tooling. It also covers project essentials such as .gitignore, code formatting, per-environment configuration, hot reload, debugging setup, and similar topics. How Webpack 4 Handles CSS github demo branch: feature/lesson5 What We Need to Do Support CSS processing Extract CSS into separate CSS files Support CSS Modules Support modern CSS features (e.g. CSS Next) Support CSS style linting Remove unused CSS Use PostCSS for tasks such as autoprefixer and css-next Minimize CSS files Loaders and Plugins We Need Loaders transform module source code. They let you preprocess files when you import or “load” a module—similar to tasks in other build tools, and a powerful way to handle frontend build steps. Loaders can turn TypeScript into JavaScript, inline images into data URLs, or even let you import CSS directly from JavaScript modules! ...

August 15, 2019 · hyyfrank

React With Webpack (4)

A webpack 4 frontend architecture series: building a scaffold from scratch, integrating React, Redux, webpack 4, gitignore, formatting, env config, HMR, debugging. webpack4 with Babel, React, CSS Module This part covers a simple setup for Babel, React, and CSS modules. We will refine later; first ship a working version. What you need Packages to install and what they do: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 "dependencies": { "react": "^16.8.1", //react package "react-dom": "^16.8.1",//the entry point to the DOM and server renderers for React "webpack": "^4.29.0", // polyfill: you can use Promise, WeakMap,Array.from,Object.assign,Array.includes.. // this is a polyfill, we need it to be a dependency "@babel/polyfill": "^7.2.5" }, "devDependencies": { //Compile object rest and spread to ES5 "@babel/plugin-proposal-object-rest-spread": "^7.3.2", // re-use of Babel's injected helper code to save on codesize. "@babel/plugin-transform-runtime": "^7.2.0", //a library that contain's Babel modular runtime //helpers and a version of regenerator-runtime. "@babel/runtime": "^7.0.0-beta.55", //babel comman line tool. "@babel/cli": "^7.2.3", "@babel/core": "^7.2.2", //a smart preset that allows you to use the latest JavaScript without needing to //micromanage which syntax transforms "@babel/preset-env": "^7.3.1", //@babel/plugin-syntax-jsx //@babel/plugin-transform-react-jsx //@babel/plugin-transform-react-display-name //@babel/plugin-transform-react-jsx-self //@babel/plugin-transform-react-jsx-source "@babel/preset-react": "^7.0.0", "babel-loader": "^8.0.5", "babel-plugin-transform-object-rest-spread": "^6.26.0", "css-loader": "^2.1.0", "html-loader": "^0.5.5", "style-loader": "^0.23.1", "html-webpack-plugin": "^4.0.0-beta.5", "clean-webpack-plugin": "^1.0.1", "webpack-cli": "^3.2.1", "webpack-dev-server": "^3.1.14" } Note @babel/polyfill belongs in dependencies because polyfills ship to production, not only at build time. Babel config .babelrc: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "presets": [ ["@babel/preset-env", { "targets": { "node": "current" } }], ["@babel/preset-react"] ], "plugins": [ ["@babel/plugin-transform-runtime"], ["@babel/plugin-proposal-object-rest-spread",{ "useBuiltIns": true }] ] } Add React support webpack.config.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const baseConfig = { entry: [ "@babel/polyfill", // required here for polyfill; can also import in source "./src/index.js" ], devtool: "cheap-module-source-map", // source map for production module: { rules: [ { test: /\.css$/, use: [ { loader: "style-loader" }, { // use CSS modules and the modules query string format loader: "css-loader?modules&localIdentName=[name]_[hash:base64:5]" } ], exclude: /node_modules/ }, { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { // run js/jsx through babel-loader loader: "babel-loader" } }, { test: /\.html$/, use: [ { loader: "html-loader" } ] } ] }, plugins: [ new CleanWebpackPlugin(["dist"]), new HtmlWebpackPlugin({ template: path.resolve(__dirname, "src", "index.html"), // template filename: "index.html", hash: true // cache busting }), new webpack.HotModuleReplacementPlugin() ], resolve: { extensions: ["*", ".js", ".jsx"] }, output: { publicPath: "/", path: path.resolve(__dirname, "dist"), filename: "[name]-bundle.js" } }; // in development, enable HMR and inline-source-map if (process.env.NODE_ENV === "development") { baseConfig.devtool = "inline-source-map"; baseConfig.devServer = { contentBase: "./dist", hot: true, open: true }; } module.exports = baseConfig; First JSX A minimal JSX component: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import React from "react"; import * as style from "../css/main.css"; const HomeComponent = () => { // test object rest/spread let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // test Array.from const arr = Array.from(new Set([1, 2, 3, 2, 1])); const arr2 = [1, [2, 3], [4, [5]]].flat(2); console.log(arr2); // test Promise const promise = new Promise((resolve, reject) => { console.log("promise"); resolve(1); }); // test Symbol const sym = Symbol(); console.log("symbol:" + sym.toString()); return ( <div> <h2>Hello React16.7.0!</h2> <div className={style.hello}>Hello CSS Module!</div> </div> ); }; export default HomeComponent; At this point the simplest React example runs. Entry index.js: ...

August 13, 2019 · hyyfrank

React With Webpack (3)

A webpack 4 frontend architecture series: building a scaffold from scratch, integrating React, Redux, webpack 4, gitignore, formatting, env config, HMR, debugging. Basics entry: configure module entry points When webpack resolves files it uses context as the base directory. Default context is the directory where you run webpack—in our project that is usually the repo root. You can also set it on the CLI, e.g. webpack --context. 1 2 3 module.exports = { context: path.resolve(__dirnaame, "app") }; Paths in entry are relative to context, which affects how later config paths are resolved. entry can be a string, array, or object. A single page might be './src/index.js'; multiple pages ['./src/firstpage.js','./src/secondpage.js']. chunk: webpack names each generated chunk. With string/array entry you get one chunk; with an object you get multiple chunks named by the object keys. Dynamic entry: For many pages and many entry points you can return an object synchronously or a Promise asynchronously: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // sync entry: () => { return { first: "./src/firstpage", second: "./src/sencordpage" }; }; // async entry: () => { return new Promise(resolve => { resolve({ first: "./src/firstpage", second: "./src/secondpage" }); }); }; output: configure emitted bundles filename: a single string such as bundle.js; for multiple chunks use placeholders like [name].js, or [id]-[name]-[hash]-[chunkhash].js (internal variables for chunk id, name, hash, content hash). chunkFilename: e.g. filenames from CommonsChunkPlugin; same placeholders as above. path: output directory for bundles. publicPath: base URL when assets are on a CDN—try your own domain to see the effect. crossOriginLoading: when async-loaded assets need CORS; often used with JSONP injected into HTML. libraryTarget & library: how the bundle is exposed as a library and under what name. libraryExport: when exporting as commonjs/commonjs2, pick which submodule to export. module: rules for processing modules rules: how webpack reads and transforms modules—usually an array of loader configs. Each rule has three parts: Which files to match: test (arrays supported), include, exclude Which loader(s) to run: babel-loader, css-loader, etc. Multiple options can be passed as an object, often options: { ... }. Order: enforce pre or post to run a loader first or last. noParse: tell webpack not to parse certain files, e.g. jquery/chartjs: 1 2 3 4 5 noParse:|jquery/chartjs/ // or as a function noParse: (content) =>{ return /jquery/chartjs/.test(content) } parser: AMD, CommonJS, SystemJS, ES6, etc. Example: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { moudle:{ rules:{ test: /\.js$/, use:['babel:loader'], parser:[ amd: false, commonjs: false, system:false, harmony:false, requireInclude: false,// disable require.include requireEnsure: false,// disable require.ensure requireContext: false,// disable require.context browserify: false, requireJs:false ] } } } resolve: how webpack finds module files alias: import shortcuts mapped to real paths: 1 2 3 4 5 resolve: { alias: { components: "./src/components"; } } import xxx from "components/xxx" becomes "./src/components/xxx". mainFields: some packages ship different builds per environment—choose which field wins. extensions: when imports omit extensions, webpack tries these suffixes: 1 2 // try .ts, then .js, then .json extentsions:['.ts','.js','.json'] modules: directories to search for dependencies; default includes node_modules. Example: 1 modules:['./src/components','node_modules'] Then import xxx from ../../../components/xxx can become import xxx from xxx. enforeExtention: if true, imports must include a file extension or resolution fails. plugins: extend webpack We already use several; imports look similar—the important part is each plugin’s options. dev-server: devServer options hot: used with hot module replacement inline: when enabled, the dev-server client drives HMR and refresh; when off, changes run in an iframe at localhost:8080/webpack-dev-server Others worth reading in the docs: historyApiFallback, contentBase, headers, host, port, allowHosts, disableHostCheck, https, clientLogLevel, compress, open others: config can export more than a plain object target: web, node, async-node, webworker, electron-main, electron-renderer Devtool: how source maps are generated watch: rebuild on file changes external: libraries not bundled by webpack, e.g. jquery ResolveLoader: where webpack discovers loaders

August 10, 2019 · hyyfrank

React With Webpack (2)

A webpack 4 frontend architecture series: building a scaffold from scratch, integrating React, Redux, webpack 4, gitignore, formatting, env config, HMR, debugging. version in package.json What is the difference between ^ and ~ in package.json? They control which versions of a dependency your project may use. For example 3.4.5 follows MAJOR.MINOR.PATCH (semantic versioning). Official site: https://semver.org/. MAJOR: incompatible API changes MINOR: backward-compatible new functionality PATCH: backward-compatible bug fixes Example: you ship API version 1.0.0, fix four bugs → 1.0.4, add backward-compatible APIs → 1.1.0, fix two more bugs → 1.1.2. If a release breaks dependents, that is 2.0.0, and so on. In package.json, ~3.4.5 means >=3.4.5 <3.5.0 (patch updates within the minor line). ^3.4.5 means >=3.4.5 <4.0.0 (any compatible 3.x). See the link above for details. npm install antd --save often records ^3.13.0—you can use any 3.x below 4.0.0. There are edge cases for 0.x versions; roughly, treat ^ like ~ for those—check the official page. Before hot module replacement (HMR), a few prerequisites. We continue from the last example: html-webpack-plugin html-webpack-plugin generates HTML for you. Without it, after a build your JS lives under dist/ (the docs often use dist, so we rename build to dist). You would still hand-edit HTML to point at the new bundle paths. This plugin generates HTML and injects references to the JS in dist. Example: ...

August 8, 2019 · hyyfrank

React With Webpack (1)

A webpack 4 frontend architecture series: building a scaffold from scratch, integrating React, Redux, webpack 4, gitignore, formatting, env config, HMR, debugging. webpack scaffold Environment First: development environment Use VS Code and github. Concepts are covered in many places already, so I will keep this brief—see the docs. OK, let us start with how to use it. We will build the features a typical project needs one by one. First, a small example to see what the bundling flow looks like—no long talk. ...

August 6, 2019 · hyyfrank