merge 0.16.1 style loader into simple-universal-style-loader
commit
696bcbe133
|
@ -0,0 +1,2 @@
|
|||
# Treats the lock file as binary & prevents conflict hell
|
||||
yarn.lock -diff
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Before creating an issue please make sure you are using the latest version of style-loader. -->
|
||||
|
||||
**Do you want to request a *feature* or report a *bug*?**
|
||||
<!-- Please ask questions on StackOverflow or the webpack Gitter (https://gitter.im/webpack/webpack). Questions will be closed. -->
|
||||
|
||||
**What is the current behavior?**
|
||||
|
||||
**If the current behavior is a bug, please provide the steps to reproduce.**
|
||||
<!-- A great way to do this is to provide your configuration via a GitHub gist. -->
|
||||
|
||||
**What is the expected behavior?**
|
||||
|
||||
**If this is a feature request, what is motivation or use case for changing the behavior?**
|
||||
|
||||
**Please mention other relevant information such as your webpack version, Node.js version and Operating System.**
|
|
@ -0,0 +1,18 @@
|
|||
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->
|
||||
|
||||
**What kind of change does this PR introduce?**
|
||||
<!-- E.g. a bugfix, feature, refactoring, build related change, etc… -->
|
||||
|
||||
**Did you add tests for your changes?**
|
||||
|
||||
**If relevant, did you update the README?**
|
||||
|
||||
**Summary**
|
||||
|
||||
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
|
||||
<!-- Try to link to an open issue for more information. -->
|
||||
|
||||
**Does this PR introduce a breaking change?**
|
||||
<!-- If this PR introduces a breaking change, please describe the impact and a migration path for existing applications. -->
|
||||
|
||||
**Other information**
|
|
@ -1,2 +1,2 @@
|
|||
/node_modules
|
||||
.idea
|
||||
.idea/
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
sudo: false
|
||||
language: node_js
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
# - os: linux
|
||||
# node_js: '7'
|
||||
# env: WEBPACK_VERSION="2.2.0" BITHOUND_CHECK=true JOB_PART=lint
|
||||
- os: linux
|
||||
node_js: '7'
|
||||
env: WEBPACK_VERSION="2.2.0" JOB_PART=test
|
||||
- os: linux
|
||||
node_js: '4.3'
|
||||
env: WEBPACK_VERSION="2.2.0" JOB_PART=test
|
||||
- os: linux
|
||||
node_js: '6'
|
||||
env: WEBPACK_VERSION="2.2.0" JOB_PART=test
|
||||
# - os: linux
|
||||
# node_js: '7'
|
||||
# env: WEBPACK_VERSION="2.2.0" JOB_PART=coverage
|
||||
before_install:
|
||||
- nvm --version
|
||||
- node --version
|
||||
before_script:
|
||||
- if [ "$WEBPACK_VERSION" ]; then yarn add webpack@^$WEBPACK_VERSION; fi
|
||||
# - if [ "$BITHOUND_CHECK" ]; then npm install -g bithound; bithound check git@github.com:$TRAVIS_REPO_SLUG.git; fi
|
||||
script:
|
||||
- yarn run travis:$JOB_PART
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
|
@ -0,0 +1,68 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
<a name="0.16.1"></a>
|
||||
## [0.16.1](https://github.com/webpack/style-loader/compare/v0.16.0...v0.16.1) (2017-03-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* negative refs ([#122](https://github.com/webpack/style-loader/issues/122)) ([f6f577a](https://github.com/webpack/style-loader/commit/f6f577a))
|
||||
|
||||
|
||||
|
||||
<a name="0.16.0"></a>
|
||||
# [0.16.0](https://github.com/webpack/style-loader/compare/v0.15.0...v0.16.0) (2017-03-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **addStyles:** update for test for old IE versions ([#196](https://github.com/webpack/style-loader/issues/196)) ([1f68495](https://github.com/webpack/style-loader/commit/1f68495))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Set custom attributes for tag in url mode ([#198](https://github.com/webpack/style-loader/issues/198)) ([2c4f427](https://github.com/webpack/style-loader/commit/2c4f427))
|
||||
|
||||
|
||||
|
||||
<a name="0.15.0"></a>
|
||||
# [0.15.0](https://github.com/webpack/style-loader/compare/v0.14.1...v0.15.0) (2017-03-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* match parens recursively on URLs to not fix embeded calls ([#192](https://github.com/webpack/style-loader/issues/192)) ([71e0908](https://github.com/webpack/style-loader/commit/71e0908))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add insertInto option ([#135](https://github.com/webpack/style-loader/issues/135)) ([6636868](https://github.com/webpack/style-loader/commit/6636868))
|
||||
|
||||
|
||||
|
||||
<a name="0.14.1"></a>
|
||||
## [0.14.1](https://github.com/webpack/style-loader/compare/v0.14.0...v0.14.1) (2017-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* syntax error in IE10 and below because of `const` keyword ([#190](https://github.com/webpack/style-loader/issues/190)) ([01080cf](https://github.com/webpack/style-loader/commit/01080cf))
|
||||
|
||||
|
||||
|
||||
<a name="0.14.0"></a>
|
||||
# [0.14.0](https://github.com/webpack/style-loader/compare/v0.13.1...v0.14.0) (2017-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Adds type attr. to the generated link element ([2a2f261](https://github.com/webpack/style-loader/commit/2a2f261))
|
||||
* **fixUrls:** add param to fix relative urls ([#186](https://github.com/webpack/style-loader/issues/186)) ([19959ee](https://github.com/webpack/style-loader/commit/19959ee))
|
||||
* **usable:** Export locals if available([#128](https://github.com/webpack/style-loader/issues/128)) ([e280cb6](https://github.com/webpack/style-loader/commit/e280cb6))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tag-attribute:** Add support for custom tag attribute ([995f3de](https://github.com/webpack/style-loader/commit/995f3de))
|
|
@ -0,0 +1,20 @@
|
|||
Copyright JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
124
README.md
124
README.md
|
@ -1,24 +1,41 @@
|
|||
# style loader for webpack
|
||||
[![npm][npm]][npm-url]
|
||||
[![node][node]][node-url]
|
||||
[![deps][deps]][deps-url]
|
||||
[![chat][chat]][chat-url]
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/webpack/webpack">
|
||||
<img width="200" height="200"
|
||||
src="https://webpack.js.org/assets/icon-square-big.svg">
|
||||
</a>
|
||||
<h1>Style Loader</h1>
|
||||
</div>
|
||||
|
||||
Adds CSS to the DOM by injecting a `<style>` tag
|
||||
|
||||
## Usage
|
||||
<h2 align="center">Install</h2>
|
||||
|
||||
```
|
||||
npm install style-loader --save-dev
|
||||
```
|
||||
|
||||
<h2 align="center">Usage</h2>
|
||||
|
||||
[Documentation: Using loaders](http://webpack.github.io/docs/using-loaders.html)
|
||||
|
||||
### Simple API
|
||||
|
||||
``` javascript
|
||||
require("simple-universal-style!raw!./file.css");
|
||||
require("simple-universal-style-loader!raw-loader!./file.css");
|
||||
// => add rules in file.css to document
|
||||
```
|
||||
|
||||
It's recommended to combine it with the [`css-loader`](https://github.com/webpack/css-loader): `require("style!css!./file.css")`.
|
||||
It's recommended to combine it with the [`css-loader`](https://github.com/webpack/css-loader): `require("simple-universal-style-loader!css-loader!./file.css")`.
|
||||
|
||||
It's also possible to add a URL instead of a CSS string:
|
||||
|
||||
``` javascript
|
||||
require("simple-universal-style/url!file!./file.css");
|
||||
require("simple-universal-style-loader/url!file-loader!./file.css");
|
||||
// => add a <link rel="stylesheet"> to file.css to document
|
||||
```
|
||||
|
||||
|
@ -26,17 +43,18 @@ require("simple-universal-style/url!file!./file.css");
|
|||
|
||||
(experimental)
|
||||
|
||||
When using [local scope CSS](https://github.com/webpack/css-loader#local-scope) the module exports the generated identifiers:
|
||||
When using [local scope CSS](https://github.com/webpack/css-loader#css-scope) the module exports the generated identifiers:
|
||||
|
||||
``` javascript
|
||||
var style = require("simple-universal-style!css!./file.css");
|
||||
var style = require("simple-universal-style-loader!css-loader!./file.css");
|
||||
style.placeholder1 === "z849f98ca812bc0d099a43e0f90184"
|
||||
```
|
||||
|
||||
### Reference-counted API
|
||||
|
||||
``` javascript
|
||||
var style = require("simple-universal-style/useable!css!./file.css");
|
||||
|
||||
var style = require("simple-universal-style-loader/useable!css-loader!./file.css");
|
||||
style.use(); // = style.ref();
|
||||
style.unuse(); // = style.unref();
|
||||
```
|
||||
|
@ -47,7 +65,7 @@ Note: Behavior is undefined when `unuse`/`unref` is called more often than `use`
|
|||
|
||||
### Server environment
|
||||
|
||||
On server side we can't load styles into the DOM but to collect them and use when assembling the layout.
|
||||
On server side we can't load styles into the DOM but to collect them and use when assembling the layout.
|
||||
|
||||
Example with React:
|
||||
|
||||
|
@ -71,13 +89,36 @@ import { getStyles } from 'simple-universal-style-loader'
|
|||
|
||||
#### `insertAt`
|
||||
|
||||
By default, the style-loader appends `<style>` elements to the end of the `<head>` tag of the page. This will cause CSS created by the loader to take priority over CSS already present in the document head. To insert style elements at the beginning of the head, set this query parameter to 'top', e.g. `require('../style.css?insertAt=top')`.
|
||||
By default, the style-loader appends `<style>` elements to the end of the style target, which is the `<head>` tag of the page unless specified by `insertInto`. This will cause CSS created by the loader to take priority over CSS already present in the target. To insert style elements at the beginning of the target, set this query parameter to 'top', e.g. `require('../style.css?insertAt=top')`.
|
||||
|
||||
#### `insertInto`
|
||||
By default, the style-loader inserts the `<style>` elements into the `<head>` tag of the page. If you want the tags to be inserted somewhere else, e.g. into a [ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot), you can specify a CSS selector for that element here, e.g. `require('../style.css?insertInto=#host::shadow>#root')`.
|
||||
|
||||
#### `singleton`
|
||||
|
||||
If defined, the style-loader will re-use a single `<style>` element, instead of adding/removing individual elements for each required module. **Note:** this option is on by default in IE9, which has strict limitations on the number of style tags allowed on a page. You can enable or disable it with the singleton query parameter (`?singleton` or `?-singleton`).
|
||||
|
||||
## Recommended configuration
|
||||
#### `convertToAbsoluteUrls`
|
||||
|
||||
If convertToAbsoluteUrls and sourceMaps are both enabled, relative urls will be converted to absolute urls right before the css is injected into the page. This resolves [an issue](https://github.com/webpack/style-loader/pull/96) where relative resources fail to load when source maps are enabled. You can enable it with the convertToAbsoluteUrls query parameter (`?convertToAbsoluteUrls`).
|
||||
|
||||
#### `attrs`
|
||||
|
||||
If defined, style-loader will attach given attributes with their values on `<style>` / `<link>` element.
|
||||
Usage:
|
||||
```javascript
|
||||
require('style-loader?{attrs:{id: "style-tag-id"}}!style.css');
|
||||
|
||||
// will create style tag <style id="style-tag-id">
|
||||
```
|
||||
Usage in `url` mode:
|
||||
```javascript
|
||||
require('style-loader/url?{attrs:{prop: "value"}}!file-loader!style.css')
|
||||
|
||||
// will create link tag <link rel="stylesheet" type="text/css" href="[path]/style.css" prop="value">
|
||||
```
|
||||
|
||||
### Recommended configuration
|
||||
|
||||
By convention the reference-counted API should be bound to `.useable.css` and the simple API to `.css` (similar to other file types, i.e. `.useable.less` and `.less`).
|
||||
|
||||
|
@ -86,22 +127,67 @@ So the recommended configuration for webpack is:
|
|||
``` javascript
|
||||
{
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.css$/, exclude: /\.useable\.css$/, loader: "simple-universal-style!css" },
|
||||
{ test: /\.useable\.css$/, loader: "simple-universal-style/useable!css" }
|
||||
]
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{ loader: "simple-universal-style-loader" },
|
||||
{ loader: "css-loader" },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.useable\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: "simple-universal-style-loader/useable"
|
||||
},
|
||||
{ loader: "css-loader" },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note** about source maps support and assets referenced with `url`: when style loader is used with ?sourceMap option, the CSS modules will be generated as `Blob`s, so relative paths don't work (they would be relative to `chrome:blob` or `chrome:devtools`). In order for assets to maintain correct paths setting `output.publicPath` property of webpack configuration must be set, so that absolute paths are generated.
|
||||
**Note** about source maps support and assets referenced with `url`: when style loader is used with ?sourceMap option, the CSS modules will be generated as `Blob`s, so relative paths don't work (they would be relative to `chrome:blob` or `chrome:devtools`). In order for assets to maintain correct paths setting `output.publicPath` property of webpack configuration must be set, so that absolute paths are generated. Alternatively you can enable the `convertToAbsoluteUrls` option mentioned above.
|
||||
|
||||
## Install
|
||||
<h2 align="center">Contributing</h2>
|
||||
|
||||
```
|
||||
npm install simple-universal-style-loader
|
||||
```
|
||||
|
||||
## License
|
||||
Don't hesitate to create a pull request. Every contribution is appreciated. In development you can start the tests by calling `npm test`.
|
||||
|
||||
MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
<h2 align="center">Maintainers</h2>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img width="150 height="150"
|
||||
src="https://avatars.githubusercontent.com/sokra?v=3">
|
||||
<br />
|
||||
<a href="https://github.com/">Tobias Koppers</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img width="150 height="150"
|
||||
src="https://avatars.githubusercontent.com/SpaceK33z?v=3">
|
||||
<br />
|
||||
<a href="https://github.com/">Kees Kluskens</a>
|
||||
</td>
|
||||
<tr>
|
||||
<tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<h2 align="center">LICENSE</h2>
|
||||
|
||||
MIT
|
||||
|
||||
[npm-url]: https://npmjs.com/package/simple-universal-style-loader
|
||||
|
||||
[node]: https://img.shields.io/node/v/style-loader.svg
|
||||
[node-url]: https://nodejs.org
|
||||
|
||||
[deps]: https://img.shields.io/npm/v/style-loader.svg
|
||||
|
|
|
@ -2,14 +2,28 @@
|
|||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
module.exports = function addStyleUrl(cssUrl) {
|
||||
|
||||
function attachTagAttrs(element, attrs) {
|
||||
Object.keys(attrs).forEach(function (key) {
|
||||
element.setAttribute(key, attrs[key]);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function addStyleUrl(cssUrl, options) {
|
||||
if(typeof DEBUG !== "undefined" && DEBUG) {
|
||||
if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options.attrs = typeof options.attrs === "object" ? options.attrs : {};
|
||||
|
||||
var styleElement = document.createElement("link");
|
||||
styleElement.rel = "stylesheet";
|
||||
styleElement.type = "text/css";
|
||||
styleElement.href = cssUrl;
|
||||
|
||||
attachTagAttrs(styleElement, options.attrs);
|
||||
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
head.appendChild(styleElement);
|
||||
if(module.hot) {
|
||||
|
|
74
addStyles.js
74
addStyles.js
|
@ -11,14 +11,28 @@ var stylesInDom = {},
|
|||
};
|
||||
},
|
||||
isOldIE = memoize(function() {
|
||||
return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
|
||||
// Test for IE <= 9 as proposed by Browserhacks
|
||||
// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
|
||||
// Tests for existence of standard globals is to allow style-loader
|
||||
// to operate correctly into non-standard environments
|
||||
// @see https://github.com/webpack-contrib/style-loader/issues/177
|
||||
return window && document && document.all && !window.atob;
|
||||
}),
|
||||
getHeadElement = memoize(function () {
|
||||
return document.head || document.getElementsByTagName("head")[0];
|
||||
getElement = (function(fn) {
|
||||
var memo = {};
|
||||
return function(selector) {
|
||||
if (typeof memo[selector] === "undefined") {
|
||||
memo[selector] = fn.call(this, selector);
|
||||
}
|
||||
return memo[selector]
|
||||
};
|
||||
})(function (styleTarget) {
|
||||
return document.querySelector(styleTarget)
|
||||
}),
|
||||
singletonElement = null,
|
||||
singletonCounter = 0,
|
||||
styleElementsInsertedAtTop = [];
|
||||
styleElementsInsertedAtTop = [],
|
||||
fixUrls = require("./fixUrls");
|
||||
|
||||
module.exports = function(list, options) {
|
||||
if(typeof DEBUG !== "undefined" && DEBUG) {
|
||||
|
@ -26,11 +40,16 @@ module.exports = function(list, options) {
|
|||
}
|
||||
|
||||
options = options || {};
|
||||
options.attrs = typeof options.attrs === "object" ? options.attrs : {};
|
||||
|
||||
// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
|
||||
// tags it will allow on a page
|
||||
if (typeof options.singleton === "undefined") options.singleton = isOldIE();
|
||||
|
||||
// By default, add <style> tags to the bottom of <head>.
|
||||
// By default, add <style> tags to the <head> element
|
||||
if (typeof options.insertInto === "undefined") options.insertInto = "head";
|
||||
|
||||
// By default, add <style> tags to the bottom of the target
|
||||
if (typeof options.insertAt === "undefined") options.insertAt = "bottom";
|
||||
|
||||
var styles = listToStyles(list);
|
||||
|
@ -57,7 +76,7 @@ module.exports = function(list, options) {
|
|||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function addStylesToDom(styles, options) {
|
||||
for(var i = 0; i < styles.length; i++) {
|
||||
|
@ -100,19 +119,22 @@ function listToStyles(list) {
|
|||
}
|
||||
|
||||
function insertStyleElement(options, styleElement) {
|
||||
var head = getHeadElement();
|
||||
var styleTarget = getElement(options.insertInto)
|
||||
if (!styleTarget) {
|
||||
throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");
|
||||
}
|
||||
var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
|
||||
if (options.insertAt === "top") {
|
||||
if(!lastStyleElementInsertedAtTop) {
|
||||
head.insertBefore(styleElement, head.firstChild);
|
||||
styleTarget.insertBefore(styleElement, styleTarget.firstChild);
|
||||
} else if(lastStyleElementInsertedAtTop.nextSibling) {
|
||||
head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
|
||||
styleTarget.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
|
||||
} else {
|
||||
head.appendChild(styleElement);
|
||||
styleTarget.appendChild(styleElement);
|
||||
}
|
||||
styleElementsInsertedAtTop.push(styleElement);
|
||||
} else if (options.insertAt === "bottom") {
|
||||
head.appendChild(styleElement);
|
||||
styleTarget.appendChild(styleElement);
|
||||
} else {
|
||||
throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
|
||||
}
|
||||
|
@ -128,18 +150,29 @@ function removeStyleElement(styleElement) {
|
|||
|
||||
function createStyleElement(options) {
|
||||
var styleElement = document.createElement("style");
|
||||
styleElement.type = "text/css";
|
||||
options.attrs.type = "text/css";
|
||||
|
||||
attachTagAttrs(styleElement, options.attrs);
|
||||
insertStyleElement(options, styleElement);
|
||||
return styleElement;
|
||||
}
|
||||
|
||||
function createLinkElement(options) {
|
||||
var linkElement = document.createElement("link");
|
||||
linkElement.rel = "stylesheet";
|
||||
options.attrs.type = "text/css";
|
||||
options.attrs.rel = "stylesheet";
|
||||
|
||||
attachTagAttrs(linkElement, options.attrs);
|
||||
insertStyleElement(options, linkElement);
|
||||
return linkElement;
|
||||
}
|
||||
|
||||
function attachTagAttrs(element, attrs) {
|
||||
Object.keys(attrs).forEach(function (key) {
|
||||
element.setAttribute(key, attrs[key]);
|
||||
});
|
||||
}
|
||||
|
||||
function addStyle(obj, options) {
|
||||
var styleElement, update, remove;
|
||||
|
||||
|
@ -155,7 +188,7 @@ function addStyle(obj, options) {
|
|||
typeof Blob === "function" &&
|
||||
typeof btoa === "function") {
|
||||
styleElement = createLinkElement(options);
|
||||
update = updateLink.bind(null, styleElement);
|
||||
update = updateLink.bind(null, styleElement, options);
|
||||
remove = function() {
|
||||
removeStyleElement(styleElement);
|
||||
if(styleElement.href)
|
||||
|
@ -226,10 +259,21 @@ function applyToTag(styleElement, obj) {
|
|||
}
|
||||
}
|
||||
|
||||
function updateLink(linkElement, obj) {
|
||||
function updateLink(linkElement, options, obj) {
|
||||
var css = obj.css;
|
||||
var sourceMap = obj.sourceMap;
|
||||
|
||||
/* If convertToAbsoluteUrls isn't defined, but sourcemaps are enabled
|
||||
and there is no publicPath defined then lets turn convertToAbsoluteUrls
|
||||
on by default. Otherwise default to the convertToAbsoluteUrls option
|
||||
directly
|
||||
*/
|
||||
var autoFixUrls = options.convertToAbsoluteUrls === undefined && sourceMap;
|
||||
|
||||
if (options.convertToAbsoluteUrls || autoFixUrls){
|
||||
css = fixUrls(css);
|
||||
}
|
||||
|
||||
if(sourceMap) {
|
||||
// http://stackoverflow.com/a/26603875
|
||||
css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
/**
|
||||
* When source maps are enabled, `style-loader` uses a link element with a data-uri to
|
||||
* embed the css on the page. This breaks all relative urls because now they are relative to a
|
||||
* bundle instead of the current page.
|
||||
*
|
||||
* One solution is to only use full urls, but that may be impossible.
|
||||
*
|
||||
* Instead, this function "fixes" the relative urls to be absolute according to the current page location.
|
||||
*
|
||||
* A rudimentary test suite is located at `test/fixUrls.js` and can be run via the `npm test` command.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = function (css) {
|
||||
// get current location
|
||||
var location = typeof window !== "undefined" && window.location;
|
||||
|
||||
if (!location) {
|
||||
throw new Error("fixUrls requires window.location");
|
||||
}
|
||||
|
||||
// blank or null?
|
||||
if (!css || typeof css !== "string") {
|
||||
return css;
|
||||
}
|
||||
|
||||
var baseUrl = location.protocol + "//" + location.host;
|
||||
var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/");
|
||||
|
||||
// convert each url(...)
|
||||
/*
|
||||
This regular expression is just a way to recursively match brackets within
|
||||
a string.
|
||||
|
||||
/url\s*\( = Match on the word "url" with any whitespace after it and then a parens
|
||||
( = Start a capturing group
|
||||
(?: = Start a non-capturing group
|
||||
[^)(] = Match anything that isn't a parentheses
|
||||
| = OR
|
||||
\( = Match a start parentheses
|
||||
(?: = Start another non-capturing groups
|
||||
[^)(]+ = Match anything that isn't a parentheses
|
||||
| = OR
|
||||
\( = Match a start parentheses
|
||||
[^)(]* = Match anything that isn't a parentheses
|
||||
\) = Match a end parentheses
|
||||
) = End Group
|
||||
*\) = Match anything and then a close parens
|
||||
) = Close non-capturing group
|
||||
* = Match anything
|
||||
) = Close capturing group
|
||||
\) = Match a close parens
|
||||
|
||||
/gi = Get all matches, not the first. Be case insensitive.
|
||||
*/
|
||||
var fixedCss = css.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi, function(fullMatch, origUrl) {
|
||||
// strip quotes (if they exist)
|
||||
var unquotedOrigUrl = origUrl
|
||||
.trim()
|
||||
.replace(/^"(.*)"$/, function(o, $1){ return $1; })
|
||||
.replace(/^'(.*)'$/, function(o, $1){ return $1; });
|
||||
|
||||
// already a full url? no change
|
||||
if (/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/)/i.test(unquotedOrigUrl)) {
|
||||
return fullMatch;
|
||||
}
|
||||
|
||||
// convert the url to a full url
|
||||
var newUrl;
|
||||
|
||||
if (unquotedOrigUrl.indexOf("//") === 0) {
|
||||
//TODO: should we add protocol?
|
||||
newUrl = unquotedOrigUrl;
|
||||
} else if (unquotedOrigUrl.indexOf("/") === 0) {
|
||||
// path should be relative to the base url
|
||||
newUrl = baseUrl + unquotedOrigUrl; // already starts with '/'
|
||||
} else {
|
||||
// path should be relative to current directory
|
||||
newUrl = currentDir + unquotedOrigUrl.replace(/^\.\//, ""); // Strip leading './'
|
||||
}
|
||||
|
||||
// send back the fixed url(...)
|
||||
return "url(" + JSON.stringify(newUrl) + ")";
|
||||
});
|
||||
|
||||
// send back the fixed css
|
||||
return fixedCss;
|
||||
};
|
2
index.js
2
index.js
|
@ -8,7 +8,7 @@ var loaderUtils = require("loader-utils"),
|
|||
module.exports = function() {};
|
||||
module.exports.pitch = function(remainingRequest) {
|
||||
if(this.cacheable) this.cacheable();
|
||||
var query = loaderUtils.parseQuery(this.query);
|
||||
var query = loaderUtils.getOptions(this) || {};
|
||||
return [
|
||||
"// style-loader: Adds some css to the DOM by adding a <style> tag",
|
||||
"",
|
||||
|
|
19
package.json
19
package.json
|
@ -1,10 +1,16 @@
|
|||
{
|
||||
"name": "simple-universal-style-loader",
|
||||
"version": "0.14.4",
|
||||
"version": "0.15.0",
|
||||
"author": "Tobias Koppers @sokra & Istvan Jano @janoist1",
|
||||
"description": "style loader module for webpack",
|
||||
"devDependencies": {
|
||||
"css-loader": "~0.8.0"
|
||||
"css-loader": "^0.27.3",
|
||||
"file-loader": "^0.10.1",
|
||||
"jsdom": "^9.11.0",
|
||||
"memory-fs": "^0.4.1",
|
||||
"mocha": "^3.2.0",
|
||||
"standard-version": "^4.0.0",
|
||||
"webpack": "^2.2.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -12,7 +18,7 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loader-utils": "^0.2.7"
|
||||
"loader-utils": "^1.0.2"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/webpack/style-loader/issues"
|
||||
|
@ -30,5 +36,10 @@
|
|||
"style",
|
||||
"loader",
|
||||
"webpack"
|
||||
]
|
||||
],
|
||||
"scripts": {
|
||||
"release": "yarn run standard-version",
|
||||
"test": "mocha",
|
||||
"travis:test": "yarn run test"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
// Node v4 requires "use strict" to allow block scoped let & const
|
||||
"use strict";
|
||||
|
||||
describe("basic tests", function() {
|
||||
var path = require("path");
|
||||
|
||||
var utils = require("./utils"),
|
||||
runCompilerTest = utils.runCompilerTest;
|
||||
|
||||
var fs;
|
||||
|
||||
var requiredCss = ".required { color: blue }",
|
||||
requiredCssTwo = ".requiredTwo { color: cyan }",
|
||||
localScopedCss = ":local(.className) { background: red; }",
|
||||
requiredStyle = `<style type="text/css">${requiredCss}</style>`,
|
||||
existingStyle = "<style>.existing { color: yellow }</style>",
|
||||
checkValue = '<div class="check">check</div>',
|
||||
rootDir = path.resolve(__dirname + "/../") + "/",
|
||||
jsdomHtml = [
|
||||
"<html>",
|
||||
"<head>",
|
||||
existingStyle,
|
||||
"</head>",
|
||||
"<body>",
|
||||
"<div class='target'>",
|
||||
checkValue,
|
||||
"</div>",
|
||||
"</body>",
|
||||
"</html>"
|
||||
].join("\n");
|
||||
|
||||
var styleLoaderOptions = {};
|
||||
var cssRule = {};
|
||||
|
||||
var defaultCssRule = {
|
||||
test: /\.css?$/,
|
||||
use: [
|
||||
{
|
||||
loader: "style-loader",
|
||||
options: styleLoaderOptions
|
||||
},
|
||||
"css-loader"
|
||||
]
|
||||
};
|
||||
|
||||
var webpackConfig = {
|
||||
entry: "./main.js",
|
||||
output: {
|
||||
filename: "bundle.js"
|
||||
},
|
||||
module: {
|
||||
rules: [cssRule]
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
// Reset all style-loader options
|
||||
for (var member in styleLoaderOptions) {
|
||||
delete styleLoaderOptions[member];
|
||||
}
|
||||
|
||||
for (var member in defaultCssRule) {
|
||||
cssRule[member] = defaultCssRule[member];
|
||||
}
|
||||
|
||||
fs = utils.setup(webpackConfig, jsdomHtml);
|
||||
|
||||
// Create a tiny file system. rootDir is used because loaders are refering to absolute paths.
|
||||
fs.mkdirpSync(rootDir);
|
||||
fs.writeFileSync(rootDir + "main.js", "var css = require('./style.css');");
|
||||
fs.writeFileSync(rootDir + "style.css", requiredCss);
|
||||
fs.writeFileSync(rootDir + "styleTwo.css", requiredCssTwo);
|
||||
fs.writeFileSync(rootDir + "localScoped.css", localScopedCss);
|
||||
}); // before each
|
||||
|
||||
it("insert at bottom", function(done) {
|
||||
let expected = [existingStyle, requiredStyle].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it insert at bottom
|
||||
|
||||
it("insert at top", function(done) {
|
||||
styleLoaderOptions.insertAt = "top";
|
||||
|
||||
let expected = [requiredStyle, existingStyle].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it insert at top
|
||||
|
||||
it("insert into", function(done) {
|
||||
let selector = "div.target";
|
||||
styleLoaderOptions.insertInto = selector;
|
||||
|
||||
let expected = [checkValue, requiredStyle].join("\n");
|
||||
|
||||
runCompilerTest(expected, done, undefined, selector);
|
||||
}); // it insert into
|
||||
|
||||
it("singleton", function(done) {
|
||||
// Setup
|
||||
styleLoaderOptions.singleton = true;
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"var a = require('./style.css');",
|
||||
"var b = require('./styleTwo.css');"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
`<style type="text/css">${requiredCss}${requiredCssTwo}</style>`
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it singleton
|
||||
|
||||
it("attrs", function(done) {
|
||||
// Setup
|
||||
styleLoaderOptions.attrs = {id: 'style-tag-id'};
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"var a = require('./style.css');"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
`<style id="${styleLoaderOptions.attrs.id}" type="text/css">${requiredCss}</style>`
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it attrs
|
||||
|
||||
it("url", function(done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader/url",
|
||||
options: {}
|
||||
},
|
||||
"file-loader"
|
||||
];
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
'<link rel="stylesheet" type="text/css" href="ec9d4f4f24028c3d51bf1e7728e632ff.css">'
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it url
|
||||
|
||||
it("url with attrs", function (done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader/url",
|
||||
options: {
|
||||
attrs: {
|
||||
'data-attr-1': 'attr-value-1',
|
||||
'data-attr-2': 'attr-value-2'
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-loader"
|
||||
];
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
'<link rel="stylesheet" type="text/css" href="ec9d4f4f24028c3d51bf1e7728e632ff.css" data-attr-1="attr-value-1" data-attr-2="attr-value-2">'
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it url with attrs
|
||||
|
||||
it("useable", function(done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader/useable"
|
||||
},
|
||||
"css-loader"
|
||||
];
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"var css = require('./style.css');",
|
||||
"var cssTwo = require('./styleTwo.css');",
|
||||
"css.use();",
|
||||
"cssTwo.use();",
|
||||
"css.unuse();"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
`<style type="text/css">${requiredCssTwo}</style>`
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it useable
|
||||
|
||||
it("useable without negative refs", function(done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader/useable"
|
||||
},
|
||||
"css-loader"
|
||||
];
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"var css = require('./style.css');",
|
||||
"css.unuse();", // ref still 0
|
||||
"css.use();", // ref 1
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
// Run
|
||||
let expected = [
|
||||
existingStyle,
|
||||
`<style type="text/css">${requiredCss}</style>`
|
||||
].join("\n");
|
||||
|
||||
runCompilerTest(expected, done);
|
||||
}); // it useable
|
||||
|
||||
it("local scope", function(done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader"
|
||||
},
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
localIdentName: '[name].[local]_[hash:base64:7]'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"css = require('./localScoped.css');"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
let expected = 'localScoped-className_3dIU6Uf';
|
||||
runCompilerTest(expected, done, function() { return this.css.className; });
|
||||
}); // it local scope
|
||||
|
||||
it("local scope, useable", function(done) {
|
||||
cssRule.use = [
|
||||
{
|
||||
loader: "style-loader/useable"
|
||||
},
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
localIdentName: '[name].[local]_[hash:base64:7]'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
fs.writeFileSync(
|
||||
rootDir + "main.js",
|
||||
[
|
||||
"css = require('./localScoped.css');"
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
let expected = 'localScoped-className_3dIU6Uf';
|
||||
runCompilerTest(expected, done, function() { return this.css.locals.className; });
|
||||
}); // it local scope
|
||||
|
||||
}); // describe
|
|
@ -0,0 +1,198 @@
|
|||
// Node v4 requires "use strict" to allow block scoped let & const
|
||||
"use strict";
|
||||
var assert = require("assert");
|
||||
var url = require('url');
|
||||
|
||||
describe("fix urls tests", function() {
|
||||
var fixUrls = require("../fixUrls");
|
||||
var defaultUrl = "https://x.y.z/a/b.html";
|
||||
|
||||
beforeEach(function() {
|
||||
global.window = {
|
||||
location: url.parse(defaultUrl)
|
||||
};
|
||||
});
|
||||
|
||||
var assertUrl = function (origCss, expectedCss, specialUrl) {
|
||||
if (specialUrl) {
|
||||
global.window = {
|
||||
location: url.parse(specialUrl)
|
||||
};
|
||||
}
|
||||
var resultCss = fixUrls(origCss, specialUrl || defaultUrl);
|
||||
expectedCss = expectedCss || origCss;
|
||||
|
||||
assert.equal(expectedCss, resultCss);
|
||||
};
|
||||
|
||||
// no change
|
||||
it("Null css is not modified", function() {
|
||||
assertUrl(null)
|
||||
});
|
||||
|
||||
it("Blank css is not modified", function() { assertUrl("") });
|
||||
|
||||
it("No url is not modified", function () { assertUrl("body { }") });
|
||||
|
||||
it("Full url isn't changed (no quotes)", function() {
|
||||
assertUrl("body { background-image:url(http://example.com/bg.jpg); }")
|
||||
});
|
||||
|
||||
it("Full url isn't changed (no quotes, spaces)", function() {
|
||||
assertUrl("body { background-image:url ( http://example.com/bg.jpg ); }");
|
||||
});
|
||||
|
||||
it("Full url isn't changed (double quotes)", function() {
|
||||
assertUrl("body { background-image:url(\"http://example.com/bg.jpg\"); }")
|
||||
});
|
||||
|
||||
it("Full url isn't changed (double quotes, spaces)", function() {
|
||||
assertUrl("body { background-image:url ( \"http://example.com/bg.jpg\" ); }")
|
||||
});
|
||||
|
||||
it("Full url isn't changed (single quotes)", function() {
|
||||
assertUrl("body { background-image:url('http://example.com/bg.jpg'); }")
|
||||
});
|
||||
|
||||
it("Full url isn't changed (single quotes, spaces)", function() {
|
||||
assertUrl("body { background-image:url ( 'http://example.com/bg.jpg' ); }")
|
||||
});
|
||||
|
||||
it("Multiple full urls are not changed", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(http://example.com/bg.jpg); }\ndiv.main { background-image:url ( 'https://www.anothersite.com/another.png' ); }"
|
||||
);
|
||||
});
|
||||
|
||||
it("Http url isn't changed", function() {
|
||||
assertUrl("body { background-image:url(http://example.com/bg.jpg); }");
|
||||
});
|
||||
|
||||
it("Https url isn't changed", function() {
|
||||
assertUrl("body { background-image:url(https://example.com/bg.jpg); }");
|
||||
});
|
||||
|
||||
it("HTTPS url isn't changed", function() {
|
||||
assertUrl("body { background-image:url(HTTPS://example.com/bg.jpg); }")
|
||||
});
|
||||
|
||||
it("File url isn't changed", function() {
|
||||
assertUrl("body { background-image:url(file:///example.com/bg.jpg); }")
|
||||
});
|
||||
|
||||
it("Double slash url isn't changed", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(//example.com/bg.jpg); }",
|
||||
"body { background-image:url(\"//example.com/bg.jpg\"); }"
|
||||
)
|
||||
});
|
||||
|
||||
it("Image data uri url isn't changed", function() {
|
||||
assertUrl("body { background-image:url(data:image/png;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg==); }")
|
||||
});
|
||||
|
||||
it("Font data uri url isn't changed", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(data:application/x-font-woff;charset=utf-8;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg); }"
|
||||
);
|
||||
});
|
||||
|
||||
// relative urls
|
||||
it("Relative url", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url (bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
|
||||
it("Relative url case sensitivity", function() {
|
||||
assertUrl(
|
||||
"body { background-image:URL (bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
|
||||
it("Relative url with path", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(c/d/bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
it("Relative url with dot slash", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(./c/d/bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
|
||||
it("Multiple relative urls", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(bg.jpg); }\ndiv.main { background-image:url(./c/d/bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/bg.jpg\"); }\ndiv.main { background-image:url(\"https://x.y.z/a/c/d/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
it("Relative url that looks like data-uri", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(data/image/png.base64); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/data/image/png.base64\"); }"
|
||||
);
|
||||
});
|
||||
|
||||
// urls with hashes
|
||||
it("Relative url with hash are not changed", function() {
|
||||
assertUrl("body { background-image:url(#bg.jpg); }");
|
||||
});
|
||||
|
||||
// rooted urls
|
||||
it("Rooted url", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(/bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
it("Rooted url with path", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(/a/b/bg.jpg); }",
|
||||
"body { background-image:url(\"https://x.y.z/a/b/bg.jpg\"); }"
|
||||
);
|
||||
});
|
||||
|
||||
//special locations
|
||||
it("Location with no path, filename only", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(bg.jpg); }",
|
||||
"body { background-image:url(\"http://x.y.z/bg.jpg\"); }",
|
||||
"http://x.y.z"
|
||||
);
|
||||
});
|
||||
|
||||
it("Location with no path, path with filename", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(a/bg.jpg); }",
|
||||
"body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }",
|
||||
"http://x.y.z"
|
||||
);
|
||||
});
|
||||
it("Location with no path, rel path with filename", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(./a/bg.jpg); }",
|
||||
"body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }",
|
||||
"http://x.y.z"
|
||||
);
|
||||
});
|
||||
it("Location with no path, root filename", function() {
|
||||
assertUrl(
|
||||
"body { background-image:url(/a/bg.jpg); }",
|
||||
"body { background-image:url(\"http://x.y.z/a/bg.jpg\"); }",
|
||||
"http://x.y.z"
|
||||
);
|
||||
});
|
||||
|
||||
it("Doesn't break inline SVG", function() {
|
||||
const svg = "url('data:image/svg+xml;charset=utf-8,<svg><feFlood flood-color=\"rgba(0,0,0,0.5)\" /></svg>')";
|
||||
|
||||
assertUrl(
|
||||
"body: { background: " + svg + " }"
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,87 @@
|
|||
// Node v4 requires "use strict" to allow block scoped let & const
|
||||
"use strict";
|
||||
|
||||
var MemoryFS = require("memory-fs");
|
||||
var realFs = require("fs");
|
||||
var webpack = require("webpack");
|
||||
var path = require("path");
|
||||
var jsdom = require("jsdom");
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var compiler;
|
||||
var jsdomHtml;
|
||||
|
||||
module.exports = {
|
||||
setup: function(webpackConfig, _jsdomHtml) {
|
||||
let fs = new MemoryFS();
|
||||
|
||||
jsdomHtml = _jsdomHtml;
|
||||
|
||||
// Makes webpack resolve style-loader to local folder instead of node_modules
|
||||
Object.assign(webpackConfig, {
|
||||
resolveLoader: {
|
||||
alias: {
|
||||
"style-loader": path.resolve(__dirname, "../")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
compiler = webpack(webpackConfig);
|
||||
|
||||
// Tell webpack to use our in-memory FS
|
||||
compiler.inputFileSystem = fs;
|
||||
compiler.outputFileSystem = fs;
|
||||
compiler.resolvers.normal.fileSystem = fs;
|
||||
compiler.resolvers.context.fileSystem = fs;
|
||||
|
||||
["readFileSync", "statSync"].forEach(fn => {
|
||||
// Preserve the reference to original function
|
||||
fs["mem" + fn] = fs[fn];
|
||||
|
||||
compiler.inputFileSystem[fn] = function(_path) {
|
||||
// Fallback to real FS if file is not in the memoryFS
|
||||
if (fs.existsSync(_path)) {
|
||||
return fs["mem" + fn].apply(fs, arguments);
|
||||
} else {
|
||||
return realFs[fn].apply(realFs, arguments);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return fs;
|
||||
},
|
||||
|
||||
/*
|
||||
* @param {string} expected - Expected value.
|
||||
* @param {function} done - Async callback from Mocha.
|
||||
* @param {function} actual - Executed in the context of jsdom window, should return a string to compare to.
|
||||
*/
|
||||
runCompilerTest: function(expected, done, actual, selector) {
|
||||
selector = selector || "head"
|
||||
compiler.run(function(err, stats) {
|
||||
if (stats.compilation.errors.length) {
|
||||
throw new Error(stats.compilation.errors);
|
||||
}
|
||||
|
||||
const bundleJs = stats.compilation.assets["bundle.js"].source();
|
||||
|
||||
jsdom.env({
|
||||
html: jsdomHtml,
|
||||
src: [bundleJs],
|
||||
virtualConsole: jsdom.createVirtualConsole().sendTo(console),
|
||||
done: function(err, window) {
|
||||
if (typeof actual === 'function') {
|
||||
assert.equal(actual.apply(window), expected);
|
||||
} else {
|
||||
assert.equal(window.document.querySelector(selector).innerHTML.trim(), expected);
|
||||
}
|
||||
// free memory associated with the window
|
||||
window.close();
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
3
url.js
3
url.js
|
@ -7,11 +7,12 @@ var loaderUtils = require("loader-utils"),
|
|||
module.exports = function() {};
|
||||
module.exports.pitch = function(remainingRequest) {
|
||||
this.cacheable && this.cacheable();
|
||||
var query = loaderUtils.getOptions(this) || {};
|
||||
return [
|
||||
"// style-loader: Adds some reference to a css file to the DOM by adding a <link> tag",
|
||||
"var update = require(" + JSON.stringify("!" + path.join(__dirname, "addStyleUrl.js")) + ")(",
|
||||
"\trequire(" + loaderUtils.stringifyRequest(this, "!!" + remainingRequest) + ")",
|
||||
");",
|
||||
", " + JSON.stringify(query) + ");",
|
||||
"// Hot Module Replacement",
|
||||
"if(module.hot) {",
|
||||
"\tmodule.hot.accept(" + loaderUtils.stringifyRequest(this, "!!" + remainingRequest) + ", function() {",
|
||||
|
|
|
@ -7,21 +7,21 @@ var loaderUtils = require("loader-utils"),
|
|||
module.exports = function() {};
|
||||
module.exports.pitch = function(remainingRequest) {
|
||||
if(this.cacheable) this.cacheable();
|
||||
var query = loaderUtils.parseQuery(this.query);
|
||||
var query = loaderUtils.getOptions(this) || {};
|
||||
return [
|
||||
"var refs = 0;",
|
||||
"var dispose;",
|
||||
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + remainingRequest) + ");",
|
||||
"if(typeof content === 'string') content = [[module.id, content, '']];",
|
||||
"if(content.locals) exports.locals = content.locals;",
|
||||
"exports.use = exports.ref = function() {",
|
||||
" if(!(refs++)) {",
|
||||
" exports.locals = content.locals;",
|
||||
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "addStyles.js")) + ")(content, " + JSON.stringify(query) + ");",
|
||||
" }",
|
||||
" return exports;",
|
||||
"};",
|
||||
"exports.unuse = exports.unref = function() {",
|
||||
" if(!(--refs)) {",
|
||||
" if(refs > 0 && !(--refs)) {",
|
||||
" dispose();",
|
||||
" dispose = null;",
|
||||
" }",
|
||||
|
|
Loading…
Reference in New Issue