Socket
Socket
Sign inDemoInstall

resolve-url-loader

Package Overview
Dependencies
20
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.0.0-alpha.1 to 4.0.0-alpha.2

CHANGELOG.md

145

index.js

@@ -9,4 +9,4 @@ /*

fs = require('fs'),
util = require('util'),
loaderUtils = require('loader-utils'),
camelcase = require('camelcase'),
SourceMapConsumer = require('source-map').SourceMapConsumer;

@@ -20,3 +20,28 @@

var PACKAGE_NAME = require('./package.json').name;
const DEPRECATED_OPTIONS = {
engine: [
'DEP_RESOLVE_URL_LOADER_OPTION_ENGINE',
'the "engine" option is deprecated, "postcss" engine is the default, using "rework" engine is not advised'
],
keepQuery: [
'DEP_RESOLVE_URL_LOADER_OPTION_KEEP_QUERY',
'"keepQuery" option has been removed, the query and/or hash are now always retained'
],
absolute: [
'DEP_RESOLVE_URL_LOADER_OPTION_ABSOLUTE',
'"absolute" option has been removed, consider the "join" option if absolute paths must be processed'
],
attempts: [
'DEP_RESOLVE_URL_LOADER_OPTION_ATTEMPTS',
'"attempts" option has been removed, consider the "join" option if search is needed'
],
includeRoot: [
'DEP_RESOLVE_URL_LOADER_OPTION_INCLUDE_ROOT',
'"includeRoot" option has been removed, consider the "join" option if search is needed'
],
fail: [
'DEP_RESOLVE_URL_LOADER_OPTION_FAIL',
'"fail" option has been removed'
]
};

@@ -44,2 +69,5 @@ /**

// infer webpack version from new loader features
var isWebpackGte5 = 'getOptions' in loader && typeof loader.getOptions === 'function';
// webpack 1: prefer loader query, else options object

@@ -49,40 +77,30 @@ // webpack 2: prefer loader options

// webpack 4: loader.options no longer defined
var options = Object.assign(
{
sourceMap: loader.sourceMap,
engine : 'postcss',
silent : false,
absolute : false,
keepQuery: false,
removeCR : false,
root : false,
debug : false,
join : joinFn.defaultJoin
},
!!loader.options && loader.options[camelcase(PACKAGE_NAME)],
loaderUtils.getOptions(loader)
);
var rawOptions = loaderUtils.getOptions(loader),
options = Object.assign(
{
fs : loader.fs,
sourceMap: loader.sourceMap,
engine : 'postcss',
silent : false,
removeCR : false,
root : false,
debug : false,
join : joinFn.defaultJoin
},
rawOptions
);
// maybe log options for the test harness
logToTestHarness(options);
// defunct options
if ('attempts' in options) {
handleAsWarning(
'loader misconfiguration',
'"attempts" option is defunct (consider "join" option if search is needed)'
if (process.env.RESOLVE_URL_LOADER_TEST_HARNESS) {
logToTestHarness(
process[process.env.RESOLVE_URL_LOADER_TEST_HARNESS],
options
);
}
if ('includeRoot' in options) {
handleAsWarning(
'loader misconfiguration',
'"includeRoot" option is defunct (consider "join" option if search is needed)'
);
// deprecated options
var deprecatedItems = Object.entries(DEPRECATED_OPTIONS).filter(([key]) => key in rawOptions);
if (deprecatedItems.length) {
deprecatedItems.forEach(([, value]) => handleAsDeprecated(...value));
}
if ('fail' in options) {
handleAsWarning(
'loader misconfiguration',
'"fail" option is defunct'
);
}

@@ -95,6 +113,6 @@ // validate join option

);
} else if (options.join.length !== 2) {
} else if (options.join.length !== 1) {
return handleAsError(
'loader misconfiguration',
'"join" Function must take exactly 2 arguments (filename and options hash)'
'"join" Function must take exactly 1 arguments (options hash)'
);

@@ -155,6 +173,11 @@ }

sourceMapConsumer = new SourceMapConsumer(absSourceMap);
} else {
handleAsWarning(
'webpack misconfiguration',
'webpack or the upstream loader did not supply a source-map'
);
}
// choose a CSS engine
var enginePath = /^\w+$/.test(options.engine) && path.join(__dirname, 'lib', 'engine', options.engine + '.js');
var enginePath = /^[\w-]+$/.test(options.engine) && path.join(__dirname, 'lib', 'engine', options.engine + '.js');
var isValidEngine = fs.existsSync(enginePath);

@@ -168,6 +191,17 @@ if (!isValidEngine) {

// allow engine to throw at initialisation
var engine;
try {
engine = require(enginePath);
} catch (error) {
return handleAsError(
'error initialising',
error
);
}
// process async
var callback = loader.async();
Promise
.resolve(require(enginePath)(loader.resourcePath, content, {
.resolve(engine(loader.resourcePath, content, {
outputSourceMap : !!options.sourceMap,

@@ -183,16 +217,19 @@ transformDeclaration: valueProcessor(loader.resourcePath, options),

function onFailure(error) {
callback(encodeError('CSS error', error));
callback(encodeError('error processing CSS', error));
}
function onSuccess(reworked) {
if (reworked) {
function onSuccess(result) {
if (result) {
// complete with source-map
// source-map sources are relative to the file being processed
// webpack4 and earlier: source-map sources are relative to the file being processed
// webpack5: source-map sources are relative to the project root but without a leading slash
if (options.sourceMap) {
var finalMap = adjustSourceMap(loader, {format: 'sourceRelative'}, reworked.map);
callback(null, reworked.content, finalMap);
var finalMap = adjustSourceMap(loader, {
format: isWebpackGte5 ? 'projectRelative' : 'sourceRelative'
}, result.map);
callback(null, result.content, finalMap);
}
// complete without source-map
else {
callback(null, reworked.content);
callback(null, result.content);
}

@@ -203,2 +240,15 @@ }

/**
* Trigger a node deprecation message for the given exception and return the original content.
* @param {string} code Deprecation code
* @param {string} message Deprecation message
* @returns {string} The original CSS content
*/
function handleAsDeprecated(code, message) {
if (!options.silent) {
util.deprecate(() => undefined, message, code)();
}
return content;
}
/**
* Push a warning for the given exception and return the original content.

@@ -230,3 +280,3 @@ * @param {string} label Summary of the error

[
PACKAGE_NAME,
'resolve-url-loader',
': ',

@@ -236,2 +286,3 @@ [label]

(typeof exception === 'string') && exception ||
Array.isArray(exception) && exception ||
(exception instanceof Error) && [exception.message, exception.stack.split('\n')[1].trim()] ||

@@ -238,0 +289,0 @@ []

@@ -70,3 +70,3 @@ /*

/**
* Create an iterable of base path strings.
* Create a hash of base path strings.
*

@@ -77,7 +77,7 @@ * Position in the declaration is supported by postcss at the position of the url() statement.

* @throws Error on invalid source map
* @returns {string[]} Iterable of base path strings possibly empty
* @returns {{subString:string, value:string, property:string, selector:string}} Hash of base path strings
*/
function getPathsAtChar(index) {
var subString = declaration.value.slice(0, index),
posParent = algerbra.sanitise(declaration.parent.source.start),
posSelector = algerbra.sanitise(declaration.parent.source.start),
posProperty = algerbra.sanitise(declaration.source.start),

@@ -87,11 +87,13 @@ posValue = algerbra.add([posProperty, algerbra.strToOffset(prefix)]),

var list = [posSubString, posValue, posProperty, posParent]
.map(positionToOriginalDirectory)
.filter(Boolean)
.filter(filterUnique);
var result = {
subString: positionToOriginalDirectory(posSubString),
value : positionToOriginalDirectory(posValue),
property : positionToOriginalDirectory(posProperty),
selector : positionToOriginalDirectory(posSelector)
};
if (list.length) {
return list;
var isValid = [result.subString, result.value, result.property, result.selector].every(Boolean);
if (isValid) {
return result;
}
// source-map present but invalid entry
else if (params.sourceMapConsumer) {

@@ -103,3 +105,3 @@ throw new Error(

} else {
return [];
throw new Error('a valid source-map is not present (ensure preceding loaders output a source-map)');
}

@@ -130,11 +132,4 @@ }

}
/**
* Simple Array filter predicate for unique elements.
*/
function filterUnique(element, i, array) {
return array.indexOf(element) === i;
}
}
module.exports = process;

@@ -8,8 +8,9 @@ /*

var path = require('path'),
convert = require('convert-source-map'),
rework = require('rework'),
visit = require('rework-visit');
convert = require('convert-source-map');
var fileProtocol = require('../file-protocol');
var rework = requireOptionalPeerDependency('rework'),
visit = requireOptionalPeerDependency('rework-visit');
/**

@@ -83,3 +84,3 @@ * Process the given CSS content into reworked CSS content.

/**
* Create a list of base path strings.
* Create a hash of base path strings.
*

@@ -89,14 +90,21 @@ * Position in the declaration is not supported since rework does not refine sourcemaps to this detail.

* @throws Error on invalid source map
* @returns {string[]} Iterable of base path strings possibly empty
* @returns {{selector:string, property:string}} Hash of base path strings
*/
function getPathsAtChar() {
var directory = positionToOriginalDirectory(declaration.position.start);
if (directory) {
return [directory];
var posSelector = declaration.parent && declaration.parent.position.start,
posProperty = declaration.position.start;
var result = {
property: positionToOriginalDirectory(posProperty),
selector: positionToOriginalDirectory(posSelector)
};
var isValid = [result.property, result.selector].every(Boolean);
if (isValid) {
return result;
}
// source-map present but invalid entry
else if (params.sourceMapConsumer) {
throw new Error('source-map information is not available at url() declaration');
} else {
return [];
throw new Error('a valid source-map is not present (ensure preceding loaders output a source-map)');
}

@@ -130,1 +138,22 @@ }

module.exports = process;
/**
* Require the given filename but fail with an error that `requireOptionalPeerDependencies` must be installed.
*
* @param moduleName The module to require
* @returns {*} The module
* @throws Error when module is not found
*/
function requireOptionalPeerDependency(moduleName) {
try {
return require(moduleName);
}
catch (error) {
if (error.message === 'Cannot find module \'' + moduleName + '\'') {
throw new Error('To use the "rework" engine you must install the optionalPeerDependencies');
}
else {
throw error;
}
}
}

@@ -9,19 +9,29 @@ /*

var maybeStream = process[process.env.RESOLVE_URL_LOADER_TEST_HARNESS];
var hasLogged = false;
function logToTestHarness(options) {
if (!!maybeStream && (typeof maybeStream === 'object') && (maybeStream instanceof stream.Writable)) {
Object.keys(options).map(eachOptionKey);
maybeStream = null; // ensure we log only once
function logToTestHarness(maybeStream, options) {
var doLogging =
!hasLogged &&
!!maybeStream &&
(typeof maybeStream === 'object') &&
(maybeStream instanceof stream.Writable);
if (doLogging) {
hasLogged = true; // ensure we log only once
Object.keys(options).forEach(eachOptionKey);
}
function eachOptionKey(key) {
var value = options[key];
var text = (typeof value === 'undefined') ?
String(value) :
(JSON.stringify(value.valueOf()) || '-unstringifyable-');
maybeStream.write(key + ': ' + text + '\n');
maybeStream.write(key + ': ' + stringify(options[key]) + '\n');
}
function stringify(value) {
try {
return JSON.stringify(value) || String(value);
} catch (e) {
return '-unstringifyable-';
}
}
}
module.exports = logToTestHarness;

@@ -8,4 +8,3 @@ /*

var path = require('path'),
loaderUtils = require('loader-utils'),
Iterator = require('es6-iterator');
loaderUtils = require('loader-utils');

@@ -16,3 +15,3 @@ /**

* @param {string} filename The current file being processed
* @param {{absolute:string, keepQuery:boolean, join:function, root:string}} options Options hash
* @param {{fs:Object, debug:function|boolean, join:function, root:string}} options Options hash
* @return {function} value processing function

@@ -24,4 +23,4 @@ */

var directory = path.dirname(filename),
join = options.join(filename, options);
var directory = path.dirname(filename),
joinProper = options.join(options);

@@ -32,3 +31,3 @@ /**

* @param {string} value A declaration value that may or may not contain a url() statement
* @param {function(number|number[]):string[]} getPathsAtChar Given an offset in the declaration value get a
* @param {function(number):Object} getPathsAtChar Given an offset in the declaration value get a
* list of possible absolute path strings

@@ -51,3 +50,3 @@ */

*
* @param {string|undefined} token A capture group or uncaptured token
* @param {string|void} token A capture group or uncaptured token
* @returns {string}

@@ -96,15 +95,12 @@ */

uri = split[0],
query = options.keepQuery ? split.slice(1).join('') : '',
absolute = testIsRelative(uri) && join(uri, new Iterator(getPathsAtChar(position))) ||
testIsAbsolute(uri) && join(uri);
query = split.slice(1).join(''),
absolute = testIsRelative(uri) && joinProper(filename, uri, false, getPathsAtChar(position)) ||
testIsAbsolute(uri) && joinProper(filename, uri, true, getPathsAtChar(position));
// use the absolute path in absolute mode or else relative path (or default to initialised)
// #6 - backslashes are not legal in URI
// not all URIs are files
if (!absolute) {
return element;
} else if (options.absolute) {
return absolute.replace(/\\/g, '/') + query;
} else {
return loaderUtils.urlToRequest(
path.relative(directory, absolute).replace(/\\/g, '/') + query
path.relative(directory, absolute).replace(/\\/g, '/') + query // #6 - backslashes are not legal in URI
);

@@ -111,0 +107,0 @@ }

{
"name": "resolve-url-loader",
"version": "4.0.0-alpha.1",
"version": "4.0.0-alpha.2",
"description": "Webpack loader that resolves relative paths in url() statements based on the original source file",

@@ -8,3 +8,4 @@ "main": "index.js",

"type": "git",
"url": "git+https://github.com/bholloway/resolve-url-loader.git"
"url": "git+https://github.com/bholloway/resolve-url-loader.git",
"directory": "packages/resolve-url-loader"
},

@@ -28,25 +29,31 @@ "keywords": [

},
"homepage": "https://github.com/bholloway/resolve-url-loader",
"homepage": "https://github.com/bholloway/resolve-url-loader/tree/master/packages/resolve-url-loader",
"engines": {
"node": ">=6.0.0"
"node": ">=8.9"
},
"files": [
"index.js",
"lib/**/+([a-z-]).js"
"lib/**/+([a-z-]).js",
"docs/**/*.*"
],
"scripts": {
"lint": "jshint --exclude **/node_modules index.js lib"
"dependencies": {
"adjust-sourcemap-loader": "^4.0.0",
"convert-source-map": "^1.7.0",
"loader-utils": "^2.0.0",
"postcss": "^7.0.35",
"source-map": "0.6.1"
},
"dependencies": {
"adjust-sourcemap-loader": "2.0.0",
"camelcase": "5.3.1",
"compose-function": "3.0.3",
"convert-source-map": "1.6.0",
"es6-iterator": "2.0.3",
"loader-utils": "1.2.3",
"postcss": "7.0.18",
"peerDependencies": {
"rework": "1.0.1",
"rework-visit": "1.0.0",
"source-map": "0.6.1"
}
"rework-visit": "1.0.0"
},
"peerDependenciesMeta": {
"rework": {
"optional": true
},
"rework-visit": {
"optional": true
}
},
"scheme": "alstroemeria"
}

@@ -5,56 +5,57 @@ # Resolve URL Loader

A **webpack loader** that rewrites relative paths in url() statements based on the original source file.
This **webpack loader** allows you to have a distributed set SCSS files and assets co-located with those SCSS files.
## Why?
## Do you organise your SCSS and assets by feature?
> **TL;DR** Making Sass work with a feature based project structure
Where are your assets?
With webpack you can import a `.scss` file (or some other compile-to-css file) and have a loader take care of the transpilation. With **Sass** (at least) this file can include a whole tree of source files into a single output.
* ✅ I want my assets all over the place, next to my SCSS files.
* ❌ My assets are in a single directory.
We can imagine a virtual `.css` file at the location the original `.scss` import. Webpack expects any **assets** found in this CSS to be relative to the original imported file.
How complicated is your SASS?
For projects with a **feature based structure** this will be a problem, since you will want to **co-locate** your assets with your `.scss` partials.
* ✅ I have a deep SASS composition with partials importing other partials.
* ✅ My asset paths are constructed by functions or `@mixin`s.
* ❌ I have a single SCSS file. The asset paths are just explicit in that.
**Example** - webpack imports `index.scss` which includes feature `foo`.
What asset paths are you using?
| files | content |
|------------------------------------|------------------------|
|src / | |
|  index.scss | `@import features/foo` |
|  features / | |
|    _foo.scss | `url(bar.png)` |
|    bar.png | |
* ✅ Fully relative `url(./foo.png)` or `url(foo.png)`
* ❌ Root relative `url(/foo.png)`
* ❌ Relative to some package or webpack root `url(~stuff/foo.png`)
* ❌ Relative to some variable which is your single asset directory `url($variable/foo.png)`
Intuatively we want the assets in partial `_foo.scss` relative to the partial, meaning `url(bar.png)`.
What webpack errors are you getting?
However webpack's `css-loader` will encounter `url(bar.png)` and expect to find `src/bar.png`. This is **not** the correct location and the build will fail.
* ✅ Webpack can't find the relative asset `foo.png` 😞
* ❌ Webpack says it doesn't have a loader for `fully/resolved/path/foo.png` 😕
Thankfully `resolve-url-loader` provides the "url rewriting" that Sass is missing. Use it _after_ the transpiler (such as [sass-loader](https://www.npmjs.com/package/sass-loader)). It makes use of the [source-map](http://www.mattzeunert.com/2016/02/14/how-do-source-maps-work.html) to find the original source file and rewrite `url()` statements.
If you can tick at least 1 item in **all of these questions** then use this loader. It will allow webpack to find assets with **fully relative paths**.
In our example it rewrites `url(bar.png)` to `url(features/bar.png)` as required.
If for any question you can't tick _any_ items then webpack should be able to already find your assets. You don't need this loader. 🤷
## Version 3
Once webpack resolves your assets (even if it complains about loading them) then this loading is working correctly. 👍
**Features**
## What's the problem with SASS?
* Use `postcss` parser by default. This is long overdue as the old `rework` parser doesn't cope with modern css.
When you use **fully relative paths** in `url()` statements then Webpack expects to find those assets next to the root SCSS file, regardless of where you specify the `url()`.
* Lots of automated tests running actual webpack builds. If you have an interesting use-case let me know.
To illustrate here are 3 simple examples of SASS and Webpack _without_ `resolve-url-loader`.
**Breaking Changes**
* Multiple options changed or deprecated.
* Removed file search "magic" in favour of `join` option.
* Errors always fail and are no longer swallowed.
* Processing absolute asset paths requires `root` option to be set.
[![the basic problem](docs/basic-problem.svg)](docs/basic-problem.svg)
**Migrating**
The first 2 cases are trivial and work fine. The asset is specified in the root SCSS file and Webpack finds it.
Initially set option `engine: 'rework'` for parity with your existing build. Once working you can remove this option **or** set `engine: 'postcss'` explicitly.
But any practical SASS composition will have nested SCSS files, as in the 3rd case. Here Webpack cannot find the asset.
Retain `keepQuery` option if you are already using it.
```
Module not found: Can't resolve './cool.png' in '/absolute/path/.../my-project/src/styles.scss'
```
The `root` option now has a different meaning. Previously it limited file search. Now it is the base path for absolute or root-relative URIs, consistent with `css-loader`. If you are already using it you can probably remove it.
The path we present to Webpack really needs to be `./subdir/cool.png` but we don't want to write that in our SCSS. 😒
If you build on Windows platform **and** your content contains absolute asset paths, then `css-loader` could fail. The `root` option here may fix the URIs before they get to `css-loader`. Try to leave it unspecified, otherwise (windows only) set to empty string `root: ''`.
Luckily we can use `resolve-url-loader` to do the **url re-writing** and make it work. 😊🎉
With functions and mixins and multiple nesting it gets more complicated. Read more detail in [how the loader works](docs/how-it-works.md). 🤓
## Getting started

@@ -80,3 +81,3 @@

**:warning: IMPORTANT**
**⚠️ IMPORTANT**
* **source-maps required** for loaders preceding `resolve-url-loader` (regardless of `devtool`).

@@ -111,138 +112,30 @@ * Always use **full loader package name** (don't omit `-loader`) otherwise you can get errors that are hard to debug.

Refer to `test` directory for full webpack configurations (as used in automated tests).
## Options
| option | type | default | | description |
|-------------|----------------------------|-------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `engine` | `'rework'`<br/>`'postcss'` | `'postcss'` | | The css parser engine. |
| `sourceMap` | boolean | `false` | | Generate a source-map. |
| `keepQuery` | boolean | `false` | | Keep query-string and/or hash suffixes.<br/>e.g. `url('./MyFont.eot?#iefix')`<br/>Be aware downstream loaders may remove query-string or hash. |
| `removeCR` | boolean | `false` | | Convert orphan CR to whitespace (postcss only).<br/>See known issues below. |
| `debug` | boolean | `false` | | Display debug information. |
| `silent` | boolean | `false` | | Do **not** display warnings. |
| `root` | string | _unset_ | | Similar to the (now defunct) option in `css-loader`.<br/>This string, possibly empty, is prepended to absolute URIs.<br/>Absolute URIs are only processed if this option is set. |
| `join` | function | _inbuilt_ | advanced | Custom join function.<br/>Use custom javascript to fix asset paths on a per-case basis.<br/>Refer to the default implementation for more information. |
| `absolute` | boolean | `false` | useless | Forces URIs to be output as absolute file paths.<br/>This is retained for historical compatibility but is likely to be removed in the future, so let me know if you use it. |
The loader should work without options but use these as required.
## How it works
| option | type | default | | description |
|-------------|----------------------------|-------------|------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `sourceMap` | boolean | `false` | | Generate an outgoing source-map. |
| `removeCR` | boolean | `false` | | Convert orphan CR to whitespace.<br/>See known issues below. |
| `debug` | boolean | `false` | | Display debug information. |
| `silent` | boolean | `false` | | Do **not** display warnings or deprecation messages. |
| `root` | string | _unset_ | | Similar to the (now defunct) option in `css-loader`.<br/>This string, possibly empty, is prepended to absolute URIs.<br/>Absolute URIs are only processed if this option is set. |
| `join` | function | _inbuilt_ | advanced | Custom join function.<br/>Use custom javascript to fix asset paths on a per-case basis.<br/>Refer to the [advanced features](docs/advanced-features.md) docs. |
| `engine` | `'rework'`<br/>`'postcss'` | `'postcss'` | deprecated | The css parser engine.<br/>Using this option produces a deprecation warning. |
A [rework](https://github.com/reworkcss/rework) or [postcss](https://postcss.org/) process is run on incoming CSS.
## Limitations
Each `url()` statement may imply an asset or may not. Generally only relative URIs are considered. However if `root` is specified then absolute or root-relative URIs are considered.
For each URI considered, the incomming source-map is consulted to determine the original file where the `url()` was specified. This becomes the `base` argument to the `join` function, whose default implementation is something like the following pseudocode.
```javascript
join(uri, base?) =>
compose(path.normalize, path.join)(base || options.join, uri);
```
Note that for absolute `uri` then the `base` is absent. In the default implementation the `root` option is used instead.
Full file search has been discontinued in version 3, however it is possible to specify a custom `join` function.
There is the added complexity that `base` may be an iterator. However `resolve-url-loader` exports some useful functions that makes a custom `join` easier.
Following `join` the URI has become an absolute path. Back-slashes are then converted to forward-slashes and the path is made relative to the initial resource being considered.
Use the `debug` option to see verbose information from the `join` function.
## Limitations / Known-issues
### Mixins
Where `url()` statements are created in a mixin the source file may then be the mixin file, and not the file calling the mixin. Obviously this is **not** the desired behaviour.
Ensure this is indeed the problem as there are many ways to misconfigure webpack. Try inlining the mixin and check that everything works correctly. However ultimately you will need to work around this.
### Compatiblity
Tested `macOS` and `Windows` for `node 6.x`.
Tested `macOS` and `Windows`.
All `webpack1`-`webpack4` with contemporaneous loaders/plugins.
All `webpack2`-`webpack4` with contemporaneous loaders/plugins using `node 8.9`. And `webpack5` with latest loaders/plugins using `node 10.0`.
Refer to `test` directory for full webpack configurations (as used in automated tests).
Refer to `test` directory for full webpack configurations as used in automated tests.
Some edge cases with `libsass` on `Windows` (see below).
Some edge cases with `libsass` on `Windows` (see [troubleshooting](docs/troubleshooting.md) docs).
### Engines
### Known issues
The `engine:postcss` is by far the more reliable option.
The `engine:rework` option is retained for historical compatibility but is likely to be removed in the future, so let me know if you use it.
If you need production css source-map it is best to avoid the combination `webpack4` with `engine:rework`. Tests show a systematic flaw in the outgoing source-map mappings.
### Absolute URIs
By "absolute URIs" we more correctly mean assets with root-relative URLs or absolute file paths.
> Absolute paths are **not** processed by default
These are **not** processed unless a `root` is specified.
However recall that any paths that _are_ processed will have windows back-slash converted to posix forward-slash. This can be useful since some webpack loaders can choke on windows paths. By using `root: ''` then `resolve-url-loader` effectively does nothing to absolute paths except change the back-slash.
It can also be useful to process absolute URIs if you have a custom `join` function and want to process all paths. However this is perhaps better done with some separate `postcss` plugin.
### Windows line breaks
Normal windows linebreaks are `CRLF`. But sometimes libsass will output single `CR` characters.
This problem is specific to multiline declarations. Refer to the [libsass bug #2693](https://github.com/sass/libsass/issues/2693).
If you have _any_ such multiline declarations preceding `url()` statements it will fail your build.
Libsass doesn't consider these orphan `CR` to be newlines but `postcss` engine does. The result being an offset in source-map line-numbers which crashes `resolve-url-loader`.
```
Module build failed: Error: resolve-url-loader: CSS error
source-map information is not available at url() declaration
```
Some users find the node-sass `linefeed` option solves the problem.
**Solutions**
* Try the node-sass [linefeed](https://github.com/sass/node-sass#linefeed--v300) option by way of `sass-loader`.
**Work arounds**
* Enable `removeCR` option [here](#option).
* Remove linebreaks in declarations.
**Diagnosis**
1. Run a stand-alone sass build `npx node-sass index.scss output.css`
2. Use a hex editor to check line endings `Format-Hex output.css`
3. Expect `0DOA` (or desired) line endings. Single `0D` confirms this problem.
## Getting help
Webpack is difficult to configure but extremely rewarding.
> Remove this loader and make sure it is not a problem with a different loader in your config (most often the case)
I am happy for you to **raise an issue** to ask a question regarding this package. However ensure you follow the check-list first.
Currently I am **not** [dogfooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) this loader in my own work. I may rely on you being able to isolate the problem in a simple example project and to help debug.
I am happy this loader helps so many people. Open-source is provided as-is so please try not project your frustrations. There are some really great people who follow this project who can help.
### Issues
Before raising a new issue:
* Remove this loader and make sure it is not a problem with a different loader in your config (most often the case).
* Check [stack overflow](http://stackoverflow.com/search?q=resolve-url-loader) for an answer.
* Review [previous issues](/issues?utf8=%E2%9C%93&q=is%3Aissue) that may be similar.
* Be prepared to create a **simple open-source project** that exhibits your problem, should the solution not be immediately obvious to us.
* (ideally) Debug some code and let me know where the problem sits.
### Pull requests
I am happy to take **pull requests**, however:
* Ensure your change is **backwards compatible** - not all users will be using the same version of Webpack or SASS that you do.
* Follow the **existing code style**. I know it is old but it maintains backwards compatibility.
* Uncomon use-cases/fixes should be opt-in per a new **option**.
* Do **not** overwrite existing variables with new values. I would prefer your change variable names elsewhere if necessary.
* Add **comments** that describe why the code is necessary - i.e. what edge case are we solving. Otherwise we may rewrite later and break your use-case.
Read the [troubleshooting](docs/troubleshooting.md) docs before raising an issue.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc