Snowpack + Rollup : A match made in heaven
Tags: javascript, snowpack, rollup, bundlers
Published: 2020-04-01 14:03:34

In this previous [post](https://dev.to/rajasegar/snowpack-how-it-works-37c), 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](https://github.com/rollup/plugins) repository and other, which are custom-built by the Snowpack team.

## Rollup
[Rollup](https://rollupjs.org) 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
- [node-resolve](https://github.com/rollup/plugins/blob/master/packages/node-resolve)
- [json](https://github.com/rollup/plugins/blob/master/packages/json)
- [commonjs](https://github.com/rollup/plugins/blob/master/packages/commonjs)
- [babel](https://github.com/rollup/rollup-plugin-babel)
- [terser](https://github.com/TrySound/rollup-plugin-terser)

### Custom-built Plugins for Snowpack
These plugins are part of the Snowpack [codebase](https://github.com/pikapkg/snowpack) itself.

- [stats](https://github.com/pikapkg/snowpack/blob/master/src/rollup-plugin-stats.ts)
- [entrypoint-alias](https://github.com/pikapkg/snowpack/blob/master/src/rollup-plugin-stats.ts)
- [remote-resolve](https://github.com/pikapkg/snowpack/blob/master/src/rollup-plugin-remote-resolve.ts)
- [remote-cdn](https://github.com/pikapkg/snowpack/blob/master/src/rollup-plugin-remote-cdn.ts)
- [treeshake-inputs](https://github.com/pikapkg/snowpack/blob/master/src/rollup-plugin-treeshake-inputs.ts)

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](https://nodejs.org/api/modules.html#modules_all_together). 

```js
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`:

```js
// 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:

```js

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.

```js
 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.

```js
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](https://github.com/fabiosantoscode/terser) under the hood.

```js
// 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](https://user-images.githubusercontent.com/622227/75009483-cc49f980-5448-11ea-81f9-bebb95a8ed07.png)

### 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

{% link https://dev.to/pika/tree-shaking-without-a-bundler-here-s-how-snowpack-does-it-1fai %}

by [Fred K. Schott](http://github.com/FredKSchott), the creator of Snowpack, where he details how Rollup plays a big role in this process.


## References:
- [Rollup](https://rollupjs.org)
- [Snowpack](https://github.com/pikapkg/snowpack)