sass-extended-importer

A Custom Sass Import Resolver with included support for Node Module Resolution, additional file extensions, and path aliases/path mapping

Usage no npm install needed!

<script type="module">
  import sassExtendedImporter from 'https://cdn.skypack.dev/sass-extended-importer';
</script>

README

Logo

A Custom Sass Import Resolver with included support for Node Module Resolution, additional file extensions, and path aliases/path mapping

Downloads per month NPM version Dependencies Contributors code style: prettier License: MIT Support on Patreon

Description

This is an implementation of the Sass Import Resolve algorithm, with added support for Node Module Resolution, and path mapping/path aliasing.

At the moment, without this Custom importer, to import files via Node Module Resolution, Sass library creators and consumers can:

  • Ship .scss, .sass, or .css files via node_modules, and let consumers depend on files directly, - but not support hoisted dependencies/monorepos.
  • Use Eyeglass

One major use case for this library is to support path mapping, which can be useful for many things, includiong simplifying import paths or dividing packages in a monorepo.

This implementation follows the convention of existing tooling and similar solutions that paths with a leading ~ will be resolved via Node Module Resolution.

Features

Backers

Become a sponsor/backer and get your logo listed here.

Bubbles Christopher Blanchard Ideal Postcodes Xerox Trent Raymond
Bubbles
Twitter: @usebubbles
Christopher Blanchard Ideal Postcodes Xerox Trent Raymond

Patreon

Patrons on Patreon

Table of Contents

Install

npm

$ npm install sass-extended-importer --save-dev

Yarn

$ yarn add sass-extended-importer --dev

pnpm

$ pnpm add sass-extended-importer --save-dev

Usage

Usage with sass

To use it with the primary sass package (dart-sass), simply import the createImporter function from this package and invoke it with the options you want to provide. Then pass it to sass is an import resolver:

import {createImporter} from "sass-extended-importer";
import sass from "sass";

sass({
    file: "/path/to/your/file.scss",
    importer: createImporter({
        // options
    })
});

Usage with node-sass

To use it with node-sass, simply import the createImporter function from this package and invoke it with the options you want to provide. Then pass it to node-sass is an import resolver:

import {createImporter} from "sass-extended-importer";
import sass from "node-sass";

sass({
    file: "/path/to/your/file.scss",
    importer: createImporter({
        // options
    })
});

Resolving files within Node Modules

Prefix the path with a ~ to indicate that the Node Module Resolution algorithm should be used:

@import "~my-library";

The resolve function will use Node Module Resolution to find the library, and then look at the main property within the related package.json file. If it points to a file, for example index.js, for which there is an identically named file with an extension of .scss, .sass , or .css, or if the main property directly points to a file with a supported extension, that file will be resolved. Alternatively, if the main property is left out, it will default to looking for a file called index with one of the supported extensions directly within the package folder.

This means that all of the following examples will work:

// Uses the package.json file's main property to look for a file with a supported extension.
// Defaults to looking for a file named `index` with a supported extension
@import "~my-library";

// Specifically looks for a file called 'index' inside the package folder, with a supported extension
@import "~my-library/index";

// Specifically looks for a file with the filename `index.scss`
@import "~my-library/index.scss";

// Looks inside the /foo folder from the package folder and for a file called `bar` with a supported extension
// (or if bar is a folder, a file within it called `index` with a supported extension)
@import "~my-library/foo/bar";

Customizing the prefix

The default prefix of ~ (tilde) is a convention used by several popular tools and is the general recommendation. However, you can customize it with the nodeModuleResolutionPrefix option for the importer:

import {createImporter} from "sass-extended-importer";
import sass from "sass";

sass({
    // ...
    importer: createImporter({
        // Use # instead of ~
        nodeModuleResolutionPrefix: "#"
    })
});

Path mapping/aliasing

You can use path mapping to map import paths to other import paths. This can be useful to simplify import statements, or if you use sass/scss/css in combination with a build pipeline that performs path mapping on your other application- or library code. For example, you might be using TypeScript's path mapping feature, and want to make sure the same paths are supported inside the sass/scss/css files you're importing from there. You can customize it with the paths option for the importer:

import {createImporter} from "sass-extended-importer";
import sass from "sass";

sass({
    // ...
    importer: createImporter({
        paths: {
            "my-alias": ["../other-folder/src/index.scss"],
            "my-alias/*": ["../other-folder/src/*"]
        }
    })
});

This allows you do write styles such as:

@import "my-alias/foo";

Which will actually be mapped to ../other-folder/src/foo.scss.

Adjusting allowed extensions

You can alter what kind of extensions that can be resolved via the extensions option for the importer:

import {createImporter} from "sass-extended-importer";
import sass from "sass";

sass({
    // ...
    importer: createImporter({
        // Use # instead of ~
        extensions: [".myextension", ".foo", ".bar"]
    })
});

Customizing the file system

If you use a virtual file system, such as one that exists within memory, you can pass it in as the fileSystem option for the importer. If you don't, it defaults to using the fs module:

import {createImporter} from "sass-extended-importer";
import sass from "sass";
import path from "path";
import {createFsFromVolume, Volume} from "memfs";

const volume = new Volume();

vol.mkdirSync("/my/directory", {recursive: true});
vol.writeFileSync("/my/directory/foo.scss", "p {color: red}");
const fileSystem = createFsFromVolume(vol);

sass({
    // ...
    importer: createImporter({
        // Use another file system
        fileSystem
    })
});

Usage with other tools and libraries

The resolve algorithm implemented by this library is also exported as as helper function, resolve, that can be used outside of just as a Custom Importer for Sass. To use it directly, simply import resolve:

import {resolve} from "sass-extended-importer";

resolve("~my-library", {cwd: "/path/to/directory"});

Contributing

Do you want to contribute? Awesome! Please follow these recommendations.

Maintainers

Frederik Wessberg
Frederik Wessberg
Twitter: @FredWessberg
Github: @wessberg
Lead Developer

FAQ

License

MIT © Frederik Wessberg (@FredWessberg) (Website)