stylus-native-loader
Version:
A super fast Stylus loader for Webpack that leverages the built-in power of Stylus
279 lines (242 loc) • 11 kB
Markdown
<p align="center">
<a href="https://stylus-lang.com/"><img src="https://stylus-lang.com/logo.svg" alt="Stylus" title="Stylus" height="120" valign="middle"></a>
<a href="https://webpack.js.org/"><img src="https://webpack.js.org/assets/icon-square-big.svg" alt="Webpack" title="Webpack" height="120" valign="middle"></a>
</p>
<p align="center">
<a href="https://www.npmjs.com/package/stylus-native-loader"><img src="https://img.shields.io/npm/v/stylus-native-loader" alt="Version"></a>
<a href="https://nodejs.org"><img src="https://img.shields.io/node/v/stylus-native-loader" alt="Node.js Version"></a>
<a href="https://packagephobia.com/result?p=stylus-native-loader"><img src="https://packagephobia.com/badge?p=stylus-native-loader" alt="Size"></a>
<a href="https://www.npmjs.com/package/stylus-native-loader"><img src="https://img.shields.io/npm/dm/stylus-native-loader" alt="Downloads"></a>
<a href="https://github.com/slightlyfaulty/stylus-native-loader/issues?q="><img src="https://img.shields.io/maintenance/yes/2025" alt="Maintained"></a>
</p>
# stylus-native-loader
A super fast [Stylus](https://stylus-lang.com/) loader for [Webpack](https://webpack.js.org/) that leverages the built-in power of Stylus. Pre-configured for modern development.
Unlike other Stylus loaders available that make use of Webpack's resolver for import path resolution (which comes with several limitations and increased overhead), stylus-native-loader relies on the powerful "native" [/require](https://stylus-lang.com/docs/import.html) capabilities of Stylus.
The result is a highly configurable, lean Stylus loader with near-baseline build speeds and unhindered /require functionality (with Webpack alias support) 🥳
## Why use this instead of [stylus-loader](https://github.com/webpack-contrib/stylus-loader)?
- It's [really fast](#benchmarks).
- It's fully compatible with Webpack 4 and 5.
- It uses Stylus native [imports](https://stylus-lang.com/docs/import.html), which are extremely fast and flexible.
- It supports Webpack [aliases](https://webpack.js.org/configuration/resolve/#resolvealias) and has automatic tilde path resolution (e.g. `~nib` = `/path/to/node_modules/nib`).
- It generates better source maps with optional content.
- It watches entire directories for changes, e.g. when adding new files with [glob imports](https://stylus-lang.com/docs/import.html#file-globbing).
- It disables all built-in vendor prefixing (by default) in favor of [PostCSS Autoprefixer](https://github.com/postcss/autoprefixer#webpack) or similar.
- It uses raw defines (by default), allowing JS object literals to be passed via options and converted to Stylus hashes.
## Benchmarks
*Build times for the [vuejs.org Stylus source code](https://github.com/vuejs/vuejs.org/tree/master/themes/vue/source/css), sorted from fastest to slowest.*
| | Min | Max | Average | Overhead |
| ------------------------------------------------------------ | -------- | -------- | ------------ |------------|
| **[stylus](https://stylus-lang.com/docs/js.html)** (no Webpack) | 93.26ms | 98.72ms | **95.97ms** | |
| **stylus-native-loader** | 101.72ms | 107.23ms | **104.37ms** | +8.76% |
| **[stylus-loader](https://github.com/webpack-contrib/stylus-loader)** | 167.18ms | 201.92ms | **180.69ms** | +88.28% |
## Getting started
To begin, install `stylus-native-loader` and `stylus`:
```sh
pnpm add -D stylus-native-loader stylus
# or
npm i -D stylus-native-loader stylus
```
Then add the loader to your **webpack.config.js**. For example, a minimal configuration might look like this:
```js
module.exports = {
module: {
rules: [
{
test: /\.styl$/,
use: ['style-loader', 'css-loader', 'stylus-native-loader'],
},
],
},
}
```
## Configuration by example
Below is an example **webpack.config.js** using all `stylus-native-loader` options. None are required.
```js
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// Any "original source" option excluding "eval" enables source map generation
// @see https://webpack.js.org/configuration/devtool/
devtool: 'source-map',
resolve: {
// All aliases are used for Stylus @import and @require path resolution
// See `alias` loader option below for adding Stylus-specific aliases
alias: {
// A standard alias that matches the first segment of an import path
// Note: Tilde (~) is not required, but is convention for stylesheet aliases
// Maps @import '~styl/*' to '/path/to/src/styl/*'
'~styl': path.join(__dirname, 'src/styl'),
// An "exact match" alias (i.e. will only match @import 'mixins')
// @see https://webpack.js.org/configuration/resolve/#resolvealias
// Maps @import 'mixins' to '/path/to/src/styl/mixins'
'mixins$': path.join(__dirname, 'src/styl/mixins'),
},
},
module: {
rules: [
{
test: /\.styl$/,
use: [
{
// Extracts CSS to a separate file
loader: MiniCssExtractPlugin.loader
},
{
// Translates CSS into CommonJS
loader: 'css-loader',
options: {
// Required for Stylus source map output
sourceMap: true,
}
},
{
// Compiles Stylus to CSS
loader: 'stylus-native-loader',
options: {
/**
* Specify Stylus plugins to use. Plugins can be passed as
* strings instead of importing them in your Webpack config.
*
* @type {string|Function|(string|Function)[]}
* @default []
*/
use: 'nib',
/**
* Add path(s) to the import lookup paths.
*
* @type {string|string[]}
* @default []
*/
include: path.join(__dirname, 'src/styl/config'),
/**
* Import the specified Stylus files/paths.
*
* @type {string|string[]}
* @default []
*/
import: [
'nib',
path.join(__dirname, 'src/styl/mixins'),
],
/**
* Define Stylus variables or functions.
*
* @type {Object}
* @default {}
*/
define: {
'$development': process.env.NODE_ENV === 'development',
'$hashvars': { foo: 'bar', bar: 'baz' },
},
/**
* The 3rd parameter of the Stylus `define()` method.
* Controls whether object literals are converted into
* hashes (true) or lists/expressions (false).
*
* @type {boolean}
* @default true
*/
defineRaw: true,
/**
* Include regular CSS on @import.
*
* @type {boolean}
* @default false
*/
includeCSS: false,
/**
* Resolve relative url()'s inside imported files.
*
* @see https://stylus-lang.com/docs/js.html#stylusresolveroptions
*
* @type {boolean|Object|'nocheck'}
* @default false
*/
resolveUrl: 'nocheck',
/**
* Aliases used for @import and @require path resolution.
* If set, webpack `resolve.alias` config is ignored.
*
* @type {Object|false}
* @default `resolve.alias`
*/
alias: {
'mixins': path.join(__dirname, 'src/styl/mixins'),
},
/**
* Non-alias imports beginning with tilde (~) are resolved
* using `require.resolve()` to find the module's base path.
*
* @example @import '~nib' resolves to '/path/to/node_modules/nib'
*
* @type {boolean}
* @default true
*/
resolveTilde: true,
/**
* Toggle built-in Stylus/Nib vendor prefixing.
* Disabled by default (prefer PostCSS Autoprefixer).
*
* @type {boolean}
* @default false
*/
vendors: false,
/**
* Toggle/configure source map generation.
* Set according to `devtool` config value by default.
*
* @see https://stylus-lang.com/docs/sourcemaps.html
*
* @type {boolean|Object}
* @default `devtool`|false
*/
sourceMap: {
// Toggle loading of source file contents into source map
content: true,
// All other Stylus "sourcemap" options can be set if needed
},
/**
* Toggle watching directories for changes. Allows new files to
* be detected in watch mode when using glob imports.
*
* @type {boolean}
* @default true
*/
watchDirs: true,
/**
* Callback that triggers right before Stylus compiles,
* allowing access to the Stylus JS API and loader context.
*
* Note: This is experimental and may prevent proper caching
* in Webpack. Use at your own risk.
*
* @see https://stylus-lang.com/docs/js.html
*
* @type {Function}
* @default undefined
*
* @param {Renderer} renderer The stylus renderer instance
* @param {Object} context The loader context object
* @param {Object} options The unified stylus options object
*/
beforeCompile(renderer, context, options) {
renderer.define('expression', { foo: 'bar', bar: 'baz' })
renderer.define('hash', { foo: 'bar', bar: 'baz' }, true)
},
/**
* Stylus has several other options/configurations that can be
* set here and will be passed directly to the Stylus compiler.
*
* @see https://stylus-lang.com/docs/js.html
* @see https://stylus-lang.com/docs/executable.html
*/
},
},
],
},
],
},
}
```
## License
[MIT](./LICENSE)