npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rework-webpack-loader

v0.2.0

Published

rework loader for webpack

Downloads

64

Readme

rework webpack loader

this is a loader for webpack that allows you to create css modules and process them with rework.

it's different than the other rework webpack loader because it treats each css file as a different webpack module.

usage

if you're not familiar with how webpack loaders work, you should checkout the main documentation first. webpack loaders allow you to transform the source of webpack modules.

rework allows you to create modular css transformations.

rework-webpack-loader works in conjunction with style-loader, but it replaces the standard css-loader.

installation

$ npm install --save-dev rework-webpack-loader

configuration

you can apply rework-webpack-loader to your css either explicitly in the require statements:

require('style!rework-webpack!./index.css');

or you can apply it to all css files via a configuration file:

var reworkLoader = require('rework-webpack-loader');
var reworkCalc = require('rework-calc');

module.exports = {
  module: {
    loaders: [
      {test: /\.css$/, loader: 'style-loader!rework-webpack-loader'}
      // ...
    ]
  },

  // the rest of the config...

  rework: {
    use [
      reworkCalc
      // ... other rework plugins ...
    ]
  }
};

advanced configuration example

rework-webpack-loader has to do some tricky things to get @import's, url's, and variables working correctly. so a full featured config might look like this:

var reworkLoader = require('rework-webpack-loader');
var reworkVars = require('rework-vars');
var reworkCalc = require('rework-calc');
var reworkCustomMedia = require('rework-custom-media');

// if you want to have something like a theme file that can override the css
// variables defined directly in the css file, make a variable map.
var varMap = reworkLoader.makeVarMap('src/index.css');

module.exports = {
  resolve: {
    // if you want to @import stuff you installed with npm, such as suit css,
    // you probably need to include `style` in your `packageMains` config
    packageMains: [
      'webpack',
      'browser',
      'web',
      'browserify',
      ['jam', 'main'],
      'style',
      'main'
    ]
    // ...
  },

  module: {
    loaders: [
      {test: /\.css$/, loader: 'style-loader!rework-webpack-loader'}
      // ...
    ]
  },

  // ...

  rework: {
    use: [
      reworkLoader.plugins.imports,
      reworkLoader.plugins.urls,
      reworkLoader.plugins.stripLocalDefs(varMap),
      reworkCustomMedia({map: varMap}),
      reworkVars({map: varMap}),
      reworkCalc
    ]
  }
};

plugin api

the plugin api is the same as rework's, with a couple additions:

  • async plugins: if you retur a promise from a plugin, rework-webpack-loader will wait for it to complete before applying the next plugin.
  • process the resulting JS: rework-webpack-loader works similarly to the default css-loader in that it transforms css into a javascript webpack module that just exports a string of css. in order for url's in the css to resolve correctly, the plugin needs to be able to edit the resulting js, not just the css, so if plugins define a module.exports.processJs function, they have the opportunity to transform the resulting javascript. check out the urls plugin for an example.

motivation

the default css-loader plugin wasn't enough for my needs because i wanted features like css variables and the calc method.

the issue with the existing rework-loader is it doesn't treat each css file as a separate webpack module, so you lose all of webpack's dependency tracking (a.k.a. the big motivator for using a module system in the first place).

why are separate modules so important?

consider an app with 3 css files:

  • base.css: css reset and utility classes
  • menu.css: styles for a re-usable css drop-down menu, which @import's base.css since it builds on those utility classes
  • app.css: styles specific to this application, which also @import's base.css since the app needs the utility classes and reset

while the last file is only ever going to be used for this app, there's a good chance you'll want to re-use the first two in other apps. so you'll also have a couple javascript modules:

  • menu.js: a dropdown-menu javascript component which require's menu.css
  • app.js: the rest of your app code, which presumably uses the menu component

your dependency tree looks something like this:

dependency tree

css preprocessors that don't treat each css file as a separate module will end up duplicating base.css in the final output. this includes the rework-loader, less-loader, and any others that inline @import statements. while they de-dupe the files during the build, since menu.css and app.css are different entry points, the preprocessor has no way of knowing about the shared files. when they output the css to webpack, there is no simple way of telling webpack which dependencies are included in the compiled module.

you also have the development-time annoyance that since webpack doesn't see these dependencies, making a change to base.css won't trigger a re-compilation.

why not just chain plugins together?

one approach for solving the dependency issue would be to just compile the source, but not trace the dependencies in the preprocessor. this could be done in less by using a .css extension in the @import statements or in rework by not including the import plugin.

now the problem becomes resolving variables. variables are especially hard to resolve at build time since they have a sort of cyclic dependency:

  • base.css might define a --base-font variable and use it to set the default font for the app (like in SUIT CSS, for example)
    • this variable is used in base.css, so we need to know it's value in order to compile the base.css module
  • app.css might reference --base-font, so it depends on base.css
  • app.css might also re-define --base-font, so now in order to compile base.css, we need that new value. now base.css depends on app.css

this is only a problem because we're trying to resolve the values at build-time, but if we had css variable support in browsers it wouldn't be an issue (we don't though).

rework-webpack-loader solves this by going through all of the css files up front and creating a mapping from variable names to values, and then using this to resolve variables during compilation. the downside is that if you change variable values, you need to restart the webpack dev server, but the upside is that it handles css variables' cyclic dependencies.

why couldn't you re-use the default css-loader?

to avoid an extra parse of the css. a little background on how webpack makes css work by default:

  • the default css-loader transforms css to a javascript module that:
    • require's all of the things the css @import'ed
    • rewrites url's to the webpack output's chunk name
      • url's are treated as relative to the css file's location
      • if they reference, say, an image, the final css will reference webpack's name for the image, which is a content hash
        • this enables long term caching of images, fonts, etc.
    • returns a string of css
  • the style-loader takes the name of a webpack module that returns a string, and creates a module that inserts a <style> element into the document with the css string as its content

if we re-use css-loader we're parsing/stringifying the css twice. admittedly this is kind of a weak reason. especially since, if you want to add something like autoprefixer, you're going to have to parse the css again anyway. you're probably better off optimizing the development build by focusing on incrementally building small modules anyway.