Skypack + Webpack = ๐ŸŽ‰

Best way to reduce bundle size is to not have third party dependencies inside source code.

ยท

3 min read

Skypack + Webpack =  ๐ŸŽ‰

Skypack

If you wonder what is skypack is, it is a open source CDN which delivers all the NPM packages up-converted to ES6 Modules.

This is huge move towards improving web, now we can use all major day to day npm packages directly in browsers, we never need npm install any more, that saves lots of space as well as time. Here is small example of how to consume packages

// index.js
import React from 'https://cdn.skypack.dev/react';
import {render} from 'https://cdn.skypack.dev/react-dom';

let element = React.createElement("h1", "Skypack is awesome!!!");
render(element, document.getElementById("root"));

All module we use from skypack are ES6 Modules, which means we don't need to use webpack or any other transpiler/bundler to convert common-js module library into browser compatible js files.

If you noticed, we did not use JSX in above example, we just used plain React api to create H1 element. If we need to use JSX then we have to use some tools to parse JSX and generate react element. There comes a need to use any transpiler/bundler.

Webpack

If you have't heard about webpack, to put it in simple term, Webpack is a bundler that provides ways to transpile and bundle the javascript, css, images, etc asserts so that it can be used in browsers.

Now webpack has added the support for emitting native ES6 Modules, with that our application code also can be transfer to browser as ES6 modules, which will give us runtime benefits as there is only very very less boilerplates / pollyfills.

Example

I played around with skypack by revamping my personal project Readme Later which I am using to keep all the useful links. My bundle size has reduced drastically since all the dependency packages are now download directly in the browser. This is huge savings.

Screenshot 2021-09-21 at 8.33.58 AM.png

Here is the webpack config to emit the ES6 Modules of our source code:

// Webpack config to emit ES6 modules
module.exports = {
  mode: "development",
  devtool: "cheap-module-source-map",
  entry: [
    paths.appIndexJs,
  ],
  experiments: {
    // The support for ES6 Moduels is experimental
    // so we need manually enable this feature
    outputModule: true,
  },
  output: {
    // Tell the webpack to emit our code as ES6 Modules
    module: true,
  },
  // Tell Webpack to that we are targetting only browsers.
  node: false,

  resolve: {...},
  module: {...},
  plugins: [...],
};

If you observed well, we have consumed react in out first example like this

import React from 'https://cdn.skypack.dev/react';

This is not cool right, we cannot copy and paste the url everywhere we consume React. What if we wish to consume React in the regular way like

import React from "react"

for that we need to change our webpack config little bit to automatically replace react with https://cdn.skypack.dev/react.

// webpack config
module.exports = {
   entry: [...],
   output: [...],
   // Tell webpack to treat react as external dependency
   // whose value is the url.
   externals: {
     "react": "https://cdn.skypack.dev/react",
   },
   // Tell webpack that all the externals dependencies are ES6 Modules
   externalsType: "module",
}

It is not good to keep the dependencies config inside the build config, so let's move it to the place where all the dependencies are handled usually package.json.

// package.json
{
  "name": "Readme Later",
  "dependencies": {...}
  "externals": {
    "development": {
      "react": "https://cdn.skypack.dev/react@v17.0.1",
    },
    "production": {
      // Pinned url optimized for production ans fast resolution
      "react": "https://cdn.skypack.dev/pin/react@v17.0.1-yH0aYV1FOvoIPeKBbHxg/mode=imports,min/optimized/react.js",
    }
  },
}

// webpack.config
const packageJson = require("./package.json");
module.exports = {
  ...
  externals: packageJson.externals[process.env.NODE_ENV],
  externalsType: "module",
  ...
}

Here is the full example repository

Advantages

  1. Reduced bundle size since it only has the source code.
  2. Faster load time.
  3. Efficient caching of dependencies since dependencies won't change often.
ย