Snowpack + Rollup : A match made in heaven

rajasegar

Rajasegar Chandran

Posted on April 1, 2020

Snowpack + Rollup : A match made in heaven

In this previous post, we saw how Snowpack works or bundles the dependencies of your application into ESM compatible modules so that you can directly import them in your HTML files.

This post explores some of the tools used by Snowpack to do the same. In fact, we will explore one tool called Rollup.

Snowpack uses Rollup to do the heavy-lifting work by making use of a bunch of Rollup plugins, some of which are official plugins part of the Rollup plugins repository and other, which are custom-built by the Snowpack team.

Rollup

Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex,
such as a library or application. It uses the new ESM (EcmaScript Modules) format using import and export included in the ES6 revision of JavaScript, instead of CommonJS or AMD.

Plugins

The following is the list of Rollup plugins used by Snowpack.

Official Rollup Plugins

Custom-built Plugins for Snowpack

These plugins are part of the Snowpack codebase itself.

Now we will take a brief look at what each and every plugin contributes to how Snowpack bundles your dependencies into ESM compatible modules for the browser.

rollup-plugin-node-resolve

This plugin locates and bundles third-party dependencies in node_modules using the Node resolution algorithm.

rollupPluginNodeResolve({
        mainFields: ['browser:module', 'module', 'browser', !isStrict && 'main'].filter(isTruthy),
        modulesOnly: isStrict, // Default: false
        extensions: ['.mjs', '.cjs', '.js', '.json'], // Default: [ '.mjs', '.js', '.json', '.node' ]
        // whether to prefer built-in modules (e.g. `fs`, `path`) or local ones with the same names
        preferBuiltins: false, // Default: true
        dedupe,
      }),

Using with @rollup/plugin-commonjs

Since most packages in your node_modules folder are probably legacy CommonJS rather than JavaScript modules, you may need to use @rollup/plugin-commonjs:

// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
  input: 'main.js',
  output: {
    file: 'bundle.js',
    format: 'iife',
    name: 'MyModule'
  },
  plugins: [resolve(), commonjs()]
};

rollup-plugin-json

This plugin converts .json files to ES6 modules.
With an accompanying file src/index.js, the local package.json file would now be importable as seen below:


rollupPluginJson({
  preferConst: true,
  indent: '  ',
  compact: isOptimized,
  namedExports: true,
}),

rollup-plugin-commonjs

A Rollup plugin to convert CommonJS modules to ES6, so they can be included in a Rollup bundle.

 rollupPluginCommonjs({
   extensions: ['.js', '.cjs'], // Default: [ '.js' ]
   namedExports: knownNamedExports,
 }),

rollup-plugin-babel

This plugin provides seamless integration between Rollup and Babel.
If you're using Babel to transpile your ES6/7 code and Rollup to generate a standalone bundle, you have a couple of options:

  • Run the code through Babel first, being careful to exclude the module transformer, or
  • Run the code through Rollup first, and then pass it to Babel.

Both approaches have disadvantages – in the first case, on top of the additional configuration complexity, you may end up with Babel's helpers repeated throughout your code.

In the second case, transpiling is likely to be slower, because transpiling a large bundle is much more work for Babel than transpiling a set of small files.

Either way, you have to worry about a place to put the intermediate files, and getting sourcemaps to behave becomes a royal pain.

Using Rollup with this plugin makes the process far easier.

rollupPluginBabel({
  compact: false,
  babelrc: false,
  configFile: false,
  presets: [
    [
      babelPresetEnv,
      {
        modules: false,
        targets: hasBrowserlistConfig
                  ? undefined
                  : '>0.75%, not ie 11, not UCAndroid >0, not OperaMini all',
      },
    ],
  ],
}),

rollup-plugin-terser

Rollup plugin to minify generated ES bundle. Uses terser under the hood.

// rollup.config.js
import { terser } from "rollup-plugin-terser";

export default {
  input: "index.js",
  output: [
    { file: "lib.js", format: "cjs" },
    { file: "lib.min.js", format: "cjs", plugins: [terser()] },
    { file: "lib.esm.js", format: "esm" }
  ]
};

rollup-plugin-stats

This plugin will display the file-size statistics when you run Snowpack with the --stat option displaying both the compressed and uncompressed size information. It displays the compressed size using gzip and brotli compressions.

snowpack --stat

Snowpack stats output

rollup-plugin-entrypoint-alias

Aliases any deep imports from a package to the package name, so that
chunking can happen more accurately.

rollup-plugin-remote-resolve

Rewrites imports for "remote packages" to point to the remote URL instead.

rollup-plugin-remote-cdn

Load import URLs from a remote CDN, sitting behind a local cache. The local cache acts as a go-between for the resolve & load step: when we get back a successful CDN resolution, we save the file to the local cache and then tell Rollup that it's safe to load from the cache in the load() hook.

rollup-plugin-treeshake-inputs

This plugin is actually used to tree-shake the dependencies used in your applications. If you are interested in knowing how Snowpack does tree-shaking without a build step, I recommend this post

by Fred K. Schott, the creator of Snowpack, where he details how Rollup plays a big role in this process.

References:

💖 💪 🙅 🚩
rajasegar
Rajasegar Chandran

Posted on April 1, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related