Features

Supported file types

Snowpack ships with built-in support for the following file types, no configuration required:

  • JavaScript (.js, .mjs)
  • TypeScript (.ts, .tsx)
  • JSX (.jsx, .tsx)
  • CSS (.css)
  • CSS Modules (.module.css)
  • Images (.svg, .jpg, .png, etc.)

To customize build behavior and support new languages check out our tooling guide

Note: Snowpack’s default build does not support JSX in .js/.ts files. If you can’t use the .jsx/.tsx file extension, you can use Babel to build your application instead.

ES Modules (ESM)

Snowpack was designed to support JavaScript’s native ES Module (ESM) syntax. ESM lets you define explicit imports & exports that browsers and build tools can better understand and optimize for. If you’re familiar with the import and export keywords in JavaScript, then you already know ESM!

// ESM Example - src/user.js
export function getUser() {
/* ... */
}

// src/index.js
import { getUser } from './user.js';

All modern browsers support ESM, so Snowpack is able to ship this code directly to the browser during development. This is what makes Snowpack’s unbundled development workflow possible.

Snowpack also lets you import non-JavaScript files directly in your application. Snowpack handles all this for you automatically so there’s nothing to configure, using the following logic:

Import NPM Packages

// Returns the React & React-DOM npm packages
import React from 'react';
import ReactDOM from 'react-dom';

Snowpack lets you import npm packages directly in the browser. Even if a package was published using a legacy format, Snowpack will up-convert the package to ESM before serving it to the browser.

When you start up your dev server or run a new build, you may see a message that Snowpack is “installing dependencies”. This means that Snowpack is converting your dependencies to run in the browser.

Import JSON

// Returns the JSON object via the default import
import json from './data.json';

Snowpack supports importing JSON files, which return the full JSON object in the default import.

Import CSS

// Loads './style.css' onto the page
import './style.css';

Snowpack supports basic CSS imports inside of your JavaScript files. When you import a CSS file via the import keyword, Snowpack will automatically apply those styles to the page. This works for CSS and compile-to-CSS languages like Sass & Less.

If you prefer, Snowpack also supports any popular CSS-in-JS library for styling.

CSS Imports (@import)

/* Import a local CSS file */
@import './style1.css';
/* Import a local Sass file (Sass build plugin still needed to compile file contents) */
@import './style2.scss';
/* Import a package CSS file */
@import 'bootstrap/dist/css/bootstrap.css';

Snowpack supports native CSS “@import” behavior with additional support for importing CSS from within packages.

Note: The actual CSS spec dictates that a “bare” import specifier like @import "package/style.css" should be treated as a relative path, equivalent to @import "./package/style.css". We intentionally break from the spec to match the same package import behavior as JavaScript imports. If you prefer the strictly native behavior with no package resolution support, use the form @import url("package/style.css") instead. Snowpack will not resolve url() imports and will leave them as-is in the final build.

Note for webpack users: If you’re migrating an existing app to snowpack, note that @import '~package/...' (URL starting with a tilde) is a syntax specific to webpack. With Snowpack you remove the ~ from your @imports.

Import CSS Modules

/* src/style.module.css */
.error {
background-color: red;
}
// 1. Converts './style.module.css' classnames to unique, scoped values.
// 2. Returns an object mapping the original classnames to their final, scoped value.
import styles from './style.module.css';

// This example uses JSX, but you can use CSS Modules with any framework.
return <div className={styles.error}>Your Error Message</div>;

Snowpack supports CSS Modules using the [name].module.css naming convention. CSS Modules work just like normal CSS imports, but with a special default styles export that maps your original classnames to unique identifiers.

Import Images & Other Assets

import img from './image.png'; // img === '/src/image.png'
import svg from './image.svg'; // svg === '/src/image.svg'

// This example uses JSX, but you can use these references with any framework.
<img src={img} />;

All other assets not explicitly mentioned above can be imported via ESM import and will return a URL reference to the final built asset. This can be useful for referencing non-JS assets by URL, like creating an image element with a src attribute pointing to that image.

Environment Variables

// `import.meta.env` - Read process.env variables in your web app
fetch(`${import.meta.env.SNOWPACK_PUBLIC_API_URL}/users`).then(...)

// Supports destructuring as well:
const {SNOWPACK_PUBLIC_API_URL} = import.meta.env;
fetch(`${SNOWPACK_PUBLIC_API_URL}/users`).then(...)

// Instead of `import.meta.env.NODE_ENV` use `import.meta.env.MODE`
if (import.meta.env.MODE === 'development') {
// ...

You can read environment variables directly in your web application via import.meta.env. If you’ve ever used process.env in Create React App or any Webpack application, this behaves exactly the same.

For your safety, Snowpack only supports environment variables that begin with SNOWPACK_PUBLIC_*. We do this because everything in your web application is sent to the browser, and we don’t want you to accidentally share sensitive keys/env variables with your public web application. Prefixing your frontend web env variables with SNOWPACK_PUBLIC_ is a good reminder that they will be shared with the world.

import.meta.env.MODE and import.meta.env.NODE_ENV are also both set to the current process.env.NODE_ENV value, so that you can change app behavior based on dev vs. build. The env value is set to development during snowpack dev and production during snowpack build. Use this in your application instead of process.env.NODE_ENV.

You can use environment variables in HTML files. All occurrences of %SNOWPACK_PUBLIC_*%, /, and production will be replaced at build time.

Remember: that these env variables are statically injected into your application for everyone at build time, and not runtime.

Hot Module Replacement

Hot Module Replacement (HMR) is the ability to update your web app during development without refreshing the page. Imagine changing some CSS, hitting save, and then instantly seeing your change reflected on the page without a refresh. That’s HMR.

Snowpack supports full HMR out-of-the-box for the following served files:

  • CSS
  • CSS Modules
  • JSON

Popular frameworks can also be set up for HMR. Create Snowpack App (CSA) ships with HMR enabled by default for all of the following frameworks. If you’re not using CSA, you can setup HMR in your application with a simple plugin or a few lines of code:

For more advanced, bare-metal HMR integrations, Snowpack created ESM-HMR, a standard HMR API for any ESM-based dev environment. Any HMR integration built for ESM-HMR will run on Snowpack and any other ESM-HMR-enabled dev server. To use the HMR API directly (via import.meta.hot) check out the ESM-HMR spec to learn more.

if (import.meta.hot) {
import.meta.hot.accept(({ module }) => {
// Accept the module, apply it to your application.
});
import.meta.hot.dispose(() => {
// Cleanup any side-effects. Optional.
});
}

HTTPS/HTTP2

npm start -- --secure

Snowpack provides an easy way to use a local HTTPS server during development through the use of the --secure flag. When enabled, Snowpack will look for a snowpack.key and snowpack.crt file in the root directory and use that to create an HTTPS server with HTTP2 support enabled.

Legacy Browser Support

You can customize the set of browsers you’d like to support via the package.json “browserslist” property, going all the way back to IE11. This will be picked up when you run snowpack build to build for production.

/* package.json */
"browserslist": ">0.75%, not ie 11, not UCAndroid >0, not OperaMini all",

If you’re worried about legacy browsers, you should also add a bundler to your production build. Check out our section on bundling for production for more info.

Note: During development (snowpack dev) we perform no transpilation for older browsers. Make sure that you’re using a modern browser during development.

Node.js Polyfills

If you depend on packages that depend on Node.js built-in modules ("fs", "path", "url", etc.) you can run Snowpack with --polyfill-node (or installOptions.polyfillNode: true in your config file). This will automatically polyfill any Node.js dependencies as much as possible for the browser. You can see the full list of supported polyfills here: https://github.com/ionic-team/rollup-plugin-node-polyfills

If you’d like to customize this polyfill behavior, skip the --polyfill-node flag and instead provide your own Rollup plugin for the installer:

// Example: If `--polyfill-node` doesn't support your use-case, you can provide your own custom Node.js polyfill behavior
module.exports = {
installOptions: {
polyfillNode: false,
rollup: {
plugins: [require('rollup-plugin-node-polyfills')({crypto: true, ...})],
},
},
};