In the previous part i showed how it is easy to add npm dependencies to the project and suggest a draft of the simple but containing everything necessary webpack.config.js and have your project under the full control.
Now let’s move to the hello world application with the hot reloading. To have the hot reload working is vital for the fast developing but there are many things to be broken, so let’s be careful from the very beginning.
Webpack will bundle js conde in the single big script to be included into the HTML code, but where the HTML code would come from? It is possible to hardcode it manually or generate automatically. In the first case there will be a problem to change src= attribute of the script tag everytime webpack generates new bundle with the new name (it is necessary to avoid caching obsolete code). Autogenerated HTML solves this problem and brings a risk of the unexpected delay if someday we would face a requirement to add something to the html.
Because of that we use semi-automated approach generating the index.html from src/index.ejs template with html-webpack-plugin.
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 73 74 75 76 77 78 79 80 81 82 83 84 |
<!DOCTYPE html> <!--[if lt IE 7 ]> <html lang="en" class="ie6" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]--> <!--[if IE 7 ]> <html lang="en" class="ie7" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]--> <!--[if IE 8 ]> <html lang="en" class="ie8" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]--> <!--[if IE 9 ]> <html lang="en" class="ie9" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>"<% } %>> <![endif]--> <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="" <% if(htmlWebpackPlugin.files.manifest) { %> manifest="<%= htmlWebpackPlugin.files.manifest %>" <% } %> > <!--<![endif]--> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <% if (htmlWebpackPlugin.files.favicon) { %> <link rel="shortcut icon" href="<%= htmlWebpackPlugin.files.favicon %>"> <% } %> <% if (htmlWebpackPlugin.options.mobile) { %> <meta name="viewport" content="width=device-width, initial-scale=1"> <% } %> <% for (var css in htmlWebpackPlugin.files.css) { %> <link href="<%= htmlWebpackPlugin.files.css[css] %>" rel="stylesheet"> <% } %> <% if (htmlWebpackPlugin.options.baseHref) { %> <base href="<%= htmlWebpackPlugin.options.baseHref %>"/> <% } %> </head> <body> <% if (htmlWebpackPlugin.options.appMountId) { %> <div id="<%= htmlWebpackPlugin.options.appMountId %>"> <% if (htmlWebpackPlugin.ssr) { %> <%- (htmlWebpackPlugin.ssr) %> <% } else { %> ... <% } %> </div> <% } %> <% if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) { %> <% for (var index in htmlWebpackPlugin.options.appMountIds) { %> <div id="<%= htmlWebpackPlugin.options.appMountIds[index] %>"></div> <% } %> <% } %> <!--[if lt IE 9]> <script> (function(){ var ef = function(){}; window.console = window.console || {log:ef,warn:ef,error:ef,dir:ef}; }()); </script> <![endif]--> <% if (htmlWebpackPlugin.options.window) { %> <script> <% for (var varName in htmlWebpackPlugin.options.window) { %> window['<%=varName%>'] = <%= JSON.stringify(htmlWebpackPlugin.options.window[varName]) %>; <% } %> </script> <% } %> <% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script> <% } %> <% if (htmlWebpackPlugin.options.devServer) { %> <script src="<%= htmlWebpackPlugin.options.devServer %>/webpack-dev-server.js"></script> <% } %> </body> </html> |
The minimal set of the react project files contains src/index.jsx and src/components/app.jsx.
Starter src/components/app.jsx it trivial:
1 2 3 4 5 |
import React from 'react'; const App = () => <div>Hello, world!</div> export default App; |
src/index.jsx seems to be a bit magic due to hot-loading, but nevertheless the most important line is module.hot.accept(()... – pay attention module.hot.accept does not accept any arguments, this enforces re-rendering of the page on any module change. With this hack we avoid unexpected stopping hot-reloading even with the console messages some modules should not/can not be hot reloaded.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React from 'react'; import ReactDOM from 'react-dom'; import App from './components/app'; const render = Component => { ReactDOM.render( <Component /> , document.getElementById('reactMount') ); }; render(App); if (module.hot) { module.hot.accept(() => { render(App); }); } |
Now
1 |
npm run build |
will create the directory dist with index.html and js bundle and
1 |
npm run watch |
will start development web server
listening on the port 8081 and watching for files to change. As soon as any file will be changed the development server will notify react application (via websocket) it should reload either the page or try to do hot-reload.