├── .gitignore ├── README.md ├── package.json ├── public └── index.html ├── src ├── bats.examples.js ├── bats.js ├── bunnies.examples.js ├── bunnies.js └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webpack-dynamic-hmr-example 2 | 3 | This is an example of how you can implement hot module replacement with 4 | `require.context`. 5 | 6 | I recorded a video you can watch about this: 7 | [youtube.com/watch?v=JGXAvgVHC5A](https://www.youtube.com/watch?v=JGXAvgVHC5A&list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-dynamic-hmr-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --mode production", 8 | "dev": "webpack-serve" 9 | }, 10 | "keywords": [], 11 | "author": "Kent C. Dodds (http://kentcdodds.com/)", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "webpack": "^4.8.3", 15 | "webpack-cli": "^2.1.4", 16 | "webpack-serve": "^1.0.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Examples 8 | 9 | 30 | 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/bats.examples.js: -------------------------------------------------------------------------------- 1 | import {bats} from './bats' 2 | 3 | export const capitalBats = bats.map(b => b.toUpperCase()) 4 | -------------------------------------------------------------------------------- /src/bats.js: -------------------------------------------------------------------------------- 1 | export const bats = ['Pteropodidae', 'Microbat', 'Flying foxes', 'Natalus'] 2 | -------------------------------------------------------------------------------- /src/bunnies.examples.js: -------------------------------------------------------------------------------- 1 | import {bunnies} from './bunnies' 2 | 3 | export const capitalBunnies = bunnies.map(b => b.toLowerCase()) 4 | -------------------------------------------------------------------------------- /src/bunnies.js: -------------------------------------------------------------------------------- 1 | export const bunnies = [ 2 | 'American Fuzzy Lop', 3 | 'Dwarf Hotot', 4 | 'Florida White Rabbit', 5 | 'Havana Rabbit' 6 | ] 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const root = document.getElementById('root') 2 | const context = require.context('.', true, /\/.*\.examples\.js/) 3 | const allThings = context.keys().map(path => context(path)) 4 | root.innerHTML = `
${JSON.stringify(allThings, null, 2)}
` 5 | 6 | if (module.hot) { 7 | // accept self and any dependencies (including those coming from context) 8 | module.hot.accept(() => { 9 | // this will be called on errors 10 | // like if you have a syntax error in a hot replaced module. 11 | console.log('there was an error in a hot replaced module') 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | 4 | const here = p => path.join(__dirname, p) 5 | 6 | module.exports = (env = process.env.NODE_ENV || 'development') => { 7 | const prod = env === 'production' 8 | const serve = JSON.parse(process.env.WEBPACK_SERVE || 'false') 9 | return removeEmpty({ 10 | context: here('src'), 11 | entry: './index.js', 12 | output: { 13 | path: here('dist'), 14 | pathinfo: true, 15 | filename: 'bundle.js', 16 | publicPath: '/' 17 | }, 18 | mode: prod ? 'production' : 'development', 19 | devtool: prod ? 'source-map' : 'cheap-module-source-map', 20 | // note the intentional absense of the HotModuleReplacementPlugin 21 | // this will be added automatically by webpack-serve 22 | serve: serve 23 | ? { 24 | content: here('./public'), 25 | clipboard: false, 26 | logLevel: 'warn', // defaults to 'info' and it's noisy 27 | hot: { 28 | hot: true, 29 | logLevel: 'warn', // defaults to 'info' and it's noisy 30 | reload: true 31 | } 32 | } 33 | : null 34 | }) 35 | } 36 | 37 | // this takes an array or object and returns a new object or array with all 38 | // null/undefined properties removed 39 | function removeEmpty(input) { 40 | if (Array.isArray(input)) { 41 | return input.filter(item => item != null) 42 | } else { 43 | return Object.entries(input).reduce((a, [k, v]) => { 44 | if (v != null) { 45 | a[k] = v 46 | } 47 | return a 48 | }, {}) 49 | } 50 | } 51 | --------------------------------------------------------------------------------