============================= Browser Bundling with Webpack ============================= In our progress towards browserless, modular TDD, we wound up a spot where...we can't run in a browser! Since browsers don't currently support modules, and certainly not CommonJS modules, we need a way to transform our code into a browser-friendly format. In this section we look at using `Webpack `_ to bundle our modular, CommonJS code into a single file fit for the browser. Along the way, we also reduce our HTTP requests by bundling our dependencies into the same file. Finally, we end in a super spot: we switch to using Webpack's development server, which re-bundles in-memory on every change *and* automatically updates your browser, hands-free. Overview ======== - Show problem with using modules in a browser *without* a module loader - Introduce and install Webpack - Generate and use a bundle, including with external dependency - Show live bundling and reloading with ``webpack-dev-server`` The Problem =========== Let's write a small web application, based around the ``incrementer`` in :doc:`../modules/index`. First, an ``index1.html`` file: .. literalinclude:: index1.html :language: html :caption: Webpack index1.html This loads a file ``app1.js``: .. literalinclude:: app1.js :language: js :caption: Webpack app1.js ...which uses CommonJS modules to import ``incrementer`` from ``./lib.js``: .. literalinclude:: lib.js :language: js :caption: Webpack lib.js PyCharm makes this easy to run. In the editor tab for ``index1.html``, mouse-over the symbol for one of the browsers and click it to open in the internal PyCharm webserver: .. image:: chrome_console.png :alt: Screenshot Chrome console As the screenshot shows, the browser console tells us we have a JavaScript error ``Uncaught ReferenceError: require is not defined``. Not surprising: browsers don't support CommonJS export/import and modules, so ``require`` is not available in a browser. We need a module bundler. We'll use Webpack. Installation ============ Our goal is to take all of our Node-style, browserless, modular code and combine it into a single ``bundle.js`` file, including jQuery as a dependency. Let's use ``npm`` to install Webpack (and its development server) as a *development* dependency: .. code-block:: bash $ npm install --save-dev webpack webpack-dev-server We can now run Webpack to "bundle" our files together: .. code-block:: bash $ node_modules/.bin/webpack app1.js -o bundle.js With this command, Webpack looks in ``app1.js`` for any ``require`` imports, then in any of those imported files for more imports, and bundles all the files into a single output file called ``bundle.js``. If we change our HTML to point at this ``bundle.js`` file: .. literalinclude:: index2.html :language: html :caption: Webpack index2.html :emphasize-lines: 8 ...then we can see ``4`` in the browser console with no errors: .. image:: chrome_console_works.png :alt: Screenshot Chrome console works .. note:: What is the ``bundle.js.map`` file that got generated? Bundlers have a habit of making the tracebacks hard to follow back to the original line in the original file. The "source map" contains all the extra information needed for this. It is only loaded when the browser has the console window open for debugging. This source map can also be inlined into the ``bundle.js`` instead of into a separate file. Including Library Code ====================== Imagine our frontend application used jQuery. In this case, included via a ``