How To Use Webpack to Host Frontend Code via External URL

I am looking to use CloudFront to store JavaScript files rather than serving them using a proxy server or using my application code (because it is faster). In this note, I am looking at how to do that.

Date Created:
Last Edited:
2 450

References



Related


What is Webpack?

Webpack

Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
  • It bundles ES Modules, CommonJS, and AMD modules
  • It can create a single bundle or multiple output chunks that are asynchronously loaded at runtime (to reduce initial loading times)
  • Dependencies are resolved during compilation, reducing the runtime size
  • Loaders can preprocess files while compiling, e.g. TypeScript to JavaScript, Handlebars to strings to compile function, images to Base64, etc.
  • Highly modular plugin system to do whatever else your application requires.

Installation

$ npm install --save-dev webpack webpack-cli

Concepts

  • Plugins
    • Webpack has a rich plugin interface. Most of the features within webpack itself use this plugin interface. This makes webpack very flexible.
  • Loaders
    • Webpack enables the use of loaders to preprocess files. This allows you to bundle any static resource way beyond JavaScript. You can write your own loaders using Node.js.
  • Performance
    • Webpack uses async I/O and has multiple caching levels. This makes webpack fats and incredibly fast on incremental compilations.
  • Module Formats
    • Webpack supports many different formats out of the box. It performs clever static analysis on the AST of the code. It even has an evaluation engine to evaluate simple expressions. This means that you can support most simple existing libraries out of the box.
  • Code Splitting
    • Webpack allows you to split your codebase into multiple chunks. Chunks are loaded asynchronously at runtime. This reduces initial loading time.
  • Optimizations
    • Webpack can do many optimizations to reduce the output size of your JavaScript by deduplicating frequently used modules, minifying, and giving you full control over what is loaded initially and what is loaded at runtime through code splitting.

Behind the scenes, webpack "transpiles" code so that it can work in all browsers. Webpack supports a configuration file for projects. The webpack cli command kicks off the transpilation process.

Notes


What I am Looking to Do

I want to serve JavaScript files through a CloudFront CDN in order to improve the the latency of requests that users experience when requesting JavaScript files.

PublicPath


The publicPath configuration option can be quite useful in a variety of scenarios. It allows you to specify the base path for all the assets within your application. Every file emitted to your output.path directory will be referenced from the output.publicPath location. This includes child chunks and any other assets that are part of you dependency graph. In development, for example, we might have an assets/ folder that lives on the same level of our index page. But what if you wanted to host all these static assets on a CND in production?

import webpack from 'webpack';

// Try the environment variable, otherwise use root
const ASSET_PATH = process.env.ASSET_PATH || '/';

export default {
output: {
publicPath: ASSET_PATH,
},

plugins: [
// This makes it possible for us to safely use env vars on our code
new webpack.DefinePlugin({
'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
}),
],
};

Another possible use case is to set the publicPath on the fly. Webpack exposes a global variable called __webpack_public_path_ that allows you to do that. In your application's entry point, you can do this:

__webpack_public_path__ = process.env.ASSET_PATH;

That's all you need. Since we're already using the DefinePlugin on our configuration, process.env.ASSET_PATH will always be defined so we can safely do that.

There are chances that you don't know what the publicPath will be in advance, and webpack can handle in automatically for you by determining the public path from variables like import.meta.url, document.currentScript, script.src or self.location. What you need is to set output.publicPath to 'auto':

module.exports = {
output: {
publicPath: 'auto',
},
};

In cases where document.currentScrpt is not supported like Internet Explorer), you have to include a polyfill like currentScript Polyfill.

Progressive Web Applications


Progressive Web Applications (or PWAs) are web apps that deliver an experience similar to native applications. there are many things that can contribute to that. Of these, the most significant is the ability for an app to be able to function when offline. This is achieved through the use of a web technology called Service Workers.

Add the Workbox webpack plugin to give the application the ability to work offline.

$  npm install workbox-webpack-plugin --save-dev
  const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');

module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management',
title: 'Progressive Web Application',
}),
new WorkboxPlugin.GenerateSW({
// these options encourage the ServiceWorkers to get in there fast
// and not allow any straggling "old" SWs to hang around
clientsClaim: true,
skipWaiting: true,
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
};

The webpack Workbox plugin results in two extra files being generated, service-worker.js and the more verbose precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js. service-worker.js is the Service Worker file and the other file is a file that service-worker.js requires so that it can run. Your own generated files will likely be different but you should have a service-worker.js file there.

Registering Our Service Worker

  import _ from 'lodash';
import printMe from './print.js';

if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('SW registered: ', registration);
}).catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
});
}

Comments

You have to be logged in to add a comment

User Comments

Insert Math Markup

ESC
About Inserting Math Content
Display Style:

Embed News Content

ESC
About Embedding News Content

Embed Youtube Video

ESC
Embedding Youtube Videos

Embed TikTok Video

ESC
Embedding TikTok Videos

Embed X Post

ESC
Embedding X Posts

Embed Instagram Post

ESC
Embedding Instagram Posts

Insert Details Element

ESC

Example Output:

Summary Title
You will be able to insert content here after confirming the title of the <details> element.

Insert Table

ESC
Customization
Align:
Preview:

Insert Horizontal Rule

#000000

Preview:


View Content At Different Sizes

ESC

Edit Style of Block Nodes

ESC

Edit the background color, default text color, margin, padding, and border of block nodes. Editable block nodes include paragraphs, headers, and lists.

#ffffff
#000000

Edit Selected Cells

Change the background color, vertical align, and borders of the cells in the current selection.

#ffffff
Vertical Align:
Border
#000000
Border Style:

Edit Table

ESC
Customization:
Align:

Upload Lexical State

ESC

Upload a .lexical file. If the file type matches the type of the current editor, then a preview will be shown below the file input.

Upload 3D Object

ESC

Upload Jupyter Notebook

ESC

Upload a Jupyter notebook and embed the resulting HTML in the text editor.

Insert Custom HTML

ESC

Edit Image Background Color

ESC
#ffffff

Insert Columns Layout

ESC
Column Type:

Select Code Language

ESC
Select Coding Language

Insert Chart

ESC

Use the search box below

Upload Previous Version of Article State

ESC