React With Webpack (8)

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 React Interacts With Middleware Functional programming ideas Curried functions defer execution. Middleware built by repeated currying accumulates arguments; with compose, you get a pipeline-style data flow. Because of closures, after applyMiddleware finishes, every middleware sees the latest store. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 export default function applyMiddleware(...middlewares) { return (createStore) => (...args) => { const store = createStore(...args) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // Basically build an array of middleware runner functions and invoke each one chain = middlewares.map(middleware => middleware(middlewareAPI)) // Enhance dispatch by running it through the middleware chain // This example uses compose to run middleware in sequence dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } } How it works Reading the source, applyMiddleware is essentially curry + compose to enhance dispatch. Quick review of curry and compose: ...

August 21, 2019 · hyyfrank

React With Webpack (6)

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. Webpack 4: Images and Fonts Code https://github.com/hyyfrank/webpack4 branch: feature/lesson7 Preparation What we need to do Support jpeg, jpg, gif, png, and similar formats ...

August 18, 2019 · hyyfrank

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