Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: webpack-contrib/style-loader
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 69e718b37e8430c2d9d4b9cf46cfd3f50cb47f56
Choose a base ref
...
head repository: webpack-contrib/style-loader
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5d73db7ae9cd8d9dee04d4273635736c347fc839
Choose a head ref

Commits on Jun 12, 2017

  1. feat: add support for iframes (options.insertInto) (#248)

    Tobias Zucali authored and michael-ciniawsky committed Jun 12, 2017
    Copy the full SHA
    25e8e89 View commit details

Commits on Jun 26, 2017

  1. Copy the full SHA
    01ceef8 View commit details

Commits on Aug 8, 2017

  1. docs: Fixes typo in readme (#258)

    kabab authored and joshwiens committed Aug 8, 2017
    Copy the full SHA
    57e171f View commit details

Commits on Aug 12, 2017

  1. docs(readme): fix typo (#260)

    piperchester authored and joshwiens committed Aug 12, 2017
    Copy the full SHA
    ce53bd9 View commit details

Commits on Sep 8, 2017

  1. Copy the full SHA
    a2ae3ac View commit details
  2. Copy the full SHA
    67120f8 View commit details

Commits on Sep 14, 2017

  1. Copy the full SHA
    378e906 View commit details

Commits on Oct 3, 2017

  1. chore(release): 0.19.0

    joshwiens committed Oct 3, 2017
    Copy the full SHA
    c9707f1 View commit details

Commits on Oct 6, 2017

  1. Copy the full SHA
    57c457d View commit details

Commits on Dec 14, 2017

  1. fix(addStyles): correctly check singleton behavior when {Boolean}

    … (`options.singleton`) (#285)
    evilebottnawi authored and michael-ciniawsky committed Dec 14, 2017

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2bfc93e View commit details
  2. chore(release): 0.19.1

    joshwiens committed Dec 14, 2017
    Copy the full SHA
    6ca2ecb View commit details

Commits on Jan 3, 2018

  1. Copy the full SHA
    a7734e6 View commit details

Commits on Jan 26, 2018

  1. Copy the full SHA
    9b46128 View commit details
  2. 2
    Copy the full SHA
    3a4cb53 View commit details
  3. Copy the full SHA
    0eb8fe7 View commit details
  4. Copy the full SHA
    ac8430c View commit details
  5. Copy the full SHA
    e0c4b19 View commit details
  6. Copy the full SHA
    23c3567 View commit details
  7. Copy the full SHA
    dda8b89 View commit details
  8. Copy the full SHA
    28f603f View commit details
  9. Copy the full SHA
    08ce425 View commit details
  10. Copy the full SHA
    5d73db7 View commit details
Showing with 6,512 additions and 3,276 deletions.
  1. +6 −6 .travis.yml
  2. +40 −0 CHANGELOG.md
  3. +60 −15 README.md
  4. +68 −20 index.js
  5. +4 −2 lib/addStyleUrl.js
  6. +34 −11 lib/addStyles.js
  7. +11 −2 options.json
  8. +6,012 −0 package-lock.json
  9. +15 −15 package.json
  10. +107 −13 test/{basicTest.js → basic.test.js}
  11. 0 test/{fixUrlsTest.js → fixUrls.test.js}
  12. +3 −0 test/insert/into.js
  13. +37 −0 test/url.test.js
  14. +37 −0 test/useable.test.js
  15. +28 −1 test/utils.js
  16. +16 −9 url.js
  17. +34 −18 useable.js
  18. +0 −3,164 yarn.lock
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -7,27 +7,27 @@ matrix:
fast_finish: true
include:
# - os: linux
# node_js: '7'
# node_js: '8'
# env: WEBPACK_VERSION="2.2.0" BITHOUND_CHECK=true JOB_PART=lint
- os: linux
node_js: '7'
node_js: '8'
env: WEBPACK_VERSION="2.2.0" JOB_PART=test
- os: linux
node_js: '4.3'
node_js: '4.8'
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'
# node_js: '8'
# 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 [ "$WEBPACK_VERSION" ]; then npm i 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
- npm run travis:$JOB_PART
after_success:
- bash <(curl -s https://codecov.io/bash)
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,46 @@

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.20.0"></a>
# [0.20.0](https://github.com/webpack-contrib/style-loader/compare/v0.19.1...v0.20.0) (2018-01-26)


### Bug Fixes

* **addStyles:** check if `HTMLIFrameElement` exist ([#296](https://github.com/webpack-contrib/style-loader/issues/296)) ([9b46128](https://github.com/webpack-contrib/style-loader/commit/9b46128))
* **index:** enable HMR in case `locals` (`css-modules`) are unchanged ([#298](https://github.com/webpack-contrib/style-loader/issues/298)) ([3a4cb53](https://github.com/webpack-contrib/style-loader/commit/3a4cb53))
* **options:** add `transform` option validation (`{String}`) ([23c3567](https://github.com/webpack-contrib/style-loader/commit/23c3567))
* **options:** support passing a `{Function}` (`options.insertInto`) ([e0c4b19](https://github.com/webpack-contrib/style-loader/commit/e0c4b19))


### Features

* support passing a `{Function}` (`options.insertInto`) ([#279](https://github.com/webpack-contrib/style-loader/issues/279)) ([0eb8fe7](https://github.com/webpack-contrib/style-loader/commit/0eb8fe7))



<a name="0.19.1"></a>
## [0.19.1](https://github.com/webpack/style-loader/compare/v0.19.0...v0.19.1) (2017-12-14)


### Bug Fixes

* **addStyles:** correctly check `singleton` behavior when `{Boolean}` (`options.singleton`) ([#285](https://github.com/webpack/style-loader/issues/285)) ([2bfc93e](https://github.com/webpack/style-loader/commit/2bfc93e))



<a name="0.19.0"></a>
# [0.19.0](https://github.com/webpack/style-loader/compare/v0.18.2...v0.19.0) (2017-10-03)


### Features

* add option to enable/disable HMR (`options.hmr`) ([#264](https://github.com/webpack/style-loader/issues/264)) ([378e906](https://github.com/webpack/style-loader/commit/378e906))
* add support for iframes (`options.insertInto`) ([#248](https://github.com/webpack/style-loader/issues/248)) ([25e8e89](https://github.com/webpack/style-loader/commit/25e8e89))
* support 'before' insertions (`options.insertAt`) ([#253](https://github.com/webpack/style-loader/issues/253)) ([67120f8](https://github.com/webpack/style-loader/commit/67120f8))



<a name="0.18.2"></a>
## [0.18.2](https://github.com/webpack/style-loader/compare/v0.18.1...v0.18.2) (2017-06-05)

75 changes: 60 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@

<h2 align="center">Install</h2>

```
```bash
npm install style-loader --save-dev
```

@@ -57,7 +57,7 @@ style.className === "z849f98ca812"

### `Url`

It's also possible to add a URL `<link href="path/to/file.css" rel="stylesheet">` instead of a inlining the CSS `{String}` with `<style></style>` tag.
It's also possible to add a URL `<link href="path/to/file.css" rel="stylesheet">` instead of inlining the CSS `{String}` with `<style></style>` tag.

```js
import url from 'file.css'
@@ -134,13 +134,30 @@ Styles are not added on `import/require()`, but instead on call to `use`/`ref`.

|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**`hmr`**|`{Boolean}`|`true`|Enable/disable Hot Module Replacement (HMR), if disabled no HMR Code will be added (good for non local development/production)|
|**`base`** |`{Number}`|`true`|Set module ID base (DLLPlugin)|
|**`attrs`**|`{Object}`|`{}`|Add custom attrs to `<style></style>`|
|**`transform`** |`{Function}`|`false`|Transform/Conditionally load CSS by passing a transform/condition function|
|**`insertAt`**|`{String}`|`bottom`|Inserts `<style></style>` at the given position|
|**`insertInto`**|`{String}`|`<head>`|Inserts `<style></style>` into the given position|
|**`insertAt`**|`{String\|Object}`|`bottom`|Inserts `<style></style>` at the given position|
|**`insertInto`**|`{String|Function}`|`<head>`|Inserts `<style></style>` into the given position|
|**`singleton`**|`{Boolean}`|`undefined`|Reuses a single `<style></style>` element, instead of adding/removing individual elements for each required module.|
|**`sourceMap`**|`{Boolean}`|`false`|Enable/Disable Sourcemaps|
|**`convertToAbsoluteUrls`**|`{Boolean}`|`false`|Coverts relative URLs to absolute urls, when source maps are enabled|
|**`convertToAbsoluteUrls`**|`{Boolean}`|`false`|Converts relative URLs to absolute urls, when source maps are enabled|

### `hmr`

Enable/disable Hot Module Replacement (HMR), if disabled no HMR Code will be added.
This could be used for non local development and production.

**webpack.config.js**
```js
{
loader: 'style-loader',
options: {
hmr: false
}
}
```

### `base`

@@ -230,7 +247,7 @@ If the return value of the `transform` function is falsy, the css will not be lo
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
transform: 'path/to/transform.js'
}
@@ -252,7 +269,7 @@ module.exports = function (css) {
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
transform: 'path/to/conditional.js'
}
@@ -278,36 +295,64 @@ By default, the style-loader appends `<style>` elements to the end of the style
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
insertAt: 'top'
}
}
```

A new `<style>` element can be inserted before a specific element by passing an object, e.g.

**webpack.config.js**
```js
{
loader: 'style-loader',
options: {
insertAt: {
before: '#id'
}
}
}
```

### `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
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 you can specify a CSS selector for that element here. If you target an [IFrame](https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement) make sure you have sufficient access rights, the styles will be injected into the content document head.

You can also pass function to override default behavior and insert styles in your container, e.g

**webpack.config.js**
```js
{
loader: 'style-loader',
options: {
insertInto: () => document.querySelector("#root"),
}
}
```

Using function you can insert the styles into a [ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot), e.g

**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
insertAt: '#host::shadow>#root'
insertInto: () => document.querySelector("#root").shadowRoot,
}
}
```

### `singleton`

If defined, the style-loader will reuse a single `<style>` element, instead of adding/removing individual elements for each required module.
If defined, the style-loader will reuse a single `<style></style>` element, instead of adding/removing individual elements for each required module.

> ℹ️ 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 option.
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
singleton: true
}
@@ -321,7 +366,7 @@ Enable/Disable source map loading
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
sourceMap: true
}
@@ -335,7 +380,7 @@ If convertToAbsoluteUrls and sourceMaps are both enabled, relative urls will be
**webpack.config.js**
```js
{
loader: 'style-loader'
loader: 'style-loader',
options: {
sourceMap: true,
convertToAbsoluteUrls: true
88 changes: 68 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/

var path = require("path");

var loaderUtils = require("loader-utils");
@@ -16,33 +15,82 @@ module.exports.pitch = function (request) {
var options = loaderUtils.getOptions(this) || {};

validateOptions(require('./options.json'), options, 'Style Loader')

options.hmr = typeof options.hmr === 'undefined' ? true : options.hmr;

// The variable is needed, because the function should be inlined.
// If is just stored it in options, JSON.stringify will quote
// the function and it would be just a string at runtime
var insertInto;

if (typeof options.insertInto === "function") {
insertInto = options.insertInto.toString();
}

// We need to check if it a string, or variable will be "undefined"
// and the loader crashes
if (typeof options.insertInto === "string") {
insertInto = '"' + options.insertInto + '"';
}

var hmr = [
// Hot Module Replacement,
"if(module.hot) {",
// When the styles change, update the <style> tags
" module.hot.accept(" + loaderUtils.stringifyRequest(this, "!!" + request) + ", function() {",
" var newContent = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
"",
" if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];",
"",
" var locals = (function(a, b) {",
" var key, idx = 0;",
"",
" for(key in a) {",
" if(!b || a[key] !== b[key]) return false;",
" idx++;",
" }",
"",
" for(key in b) idx--;",
"",
" return idx === 0;",
" }(content.locals, newContent.locals));",
"",
// This error is caught and not shown and causes a full reload
" if(!locals) throw new Error('Aborting CSS HMR due to changed css-modules locals.');",
"",
" update(newContent);",
" });",
"",
// When the module is disposed, remove the <style> tags
" module.hot.dispose(function() { update(); });",
"}"
].join("\n");

return [
"// style-loader: Adds some css to the DOM by adding a <style> tag",
// Style Loader
// Adds CSS to the DOM by adding a <style> tag
"",
"// load the styles",
// Load styles
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
"",
"if(typeof content === 'string') content = [[module.id, content, '']];",
"// Prepare cssTransformation",
"",
// Transform styles",
"var transform;",
options.transform ? "transform = require(" + loaderUtils.stringifyRequest(this, "!" + path.resolve(options.transform)) + ");" : "",
"var insertInto;",
"",
options.transform ? "transform = require(" + loaderUtils.stringifyRequest(this, "!" + path.resolve(options.transform)) + ");" : "",
"",
"var options = " + JSON.stringify(options),
"options.transform = transform",
"// add the styles to the DOM",
"",
"options.transform = transform",
"options.insertInto = " + insertInto + ";",
"",
// Add styles to the DOM
"var update = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, options);",
"",
"if(content.locals) module.exports = content.locals;",
"// Hot Module Replacement",
"if(module.hot) {",
" // When the styles change, update the <style> tags",
" if(!content.locals) {",
" module.hot.accept(" + loaderUtils.stringifyRequest(this, "!!" + request) + ", function() {",
" var newContent = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
" if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];",
" update(newContent);",
" });",
" }",
" // When the module is disposed, remove the <style> tags",
" module.hot.dispose(function() { update(); });",
"}"
"",
options.hmr ? hmr : ""
].join("\n");
};
6 changes: 4 additions & 2 deletions lib/addStyleUrl.js
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ module.exports = function addStyleUrl (url, options) {

options.attrs = typeof options.attrs === "object" ? options.attrs : {};

options.hmr = typeof options.hmr === 'undefined' ? true : options.hmr;

var link = document.createElement("link");

link.rel = "stylesheet";
@@ -30,7 +32,7 @@ module.exports = function addStyleUrl (url, options) {

head.appendChild(link);

if (module.hot) {
if (options.hmr && module.hot) {
return function(url) {
if(typeof url === "string") {
link.href = url;
@@ -39,4 +41,4 @@ module.exports = function addStyleUrl (url, options) {
}
};
}
}
}
45 changes: 34 additions & 11 deletions lib/addStyles.js
Original file line number Diff line number Diff line change
@@ -23,19 +23,39 @@ var isOldIE = memoize(function () {
return window && document && document.all && !window.atob;
});

var getTarget = function (target) {
return document.querySelector(target);
};

var getElement = (function (fn) {
var memo = {};

return function(selector) {
if (typeof memo[selector] === "undefined") {
memo[selector] = fn.call(this, selector);
return function(target) {
// If passing function in options, then use it for resolve "head" element.
// Useful for Shadow Root style i.e
// {
// insertInto: function () { return document.querySelector("#foo").shadowRoot }
// }
if (typeof target === 'function') {
return target();
}
if (typeof memo[target] === "undefined") {
var styleTarget = getTarget.call(this, target);
// Special case to return head of iframe instead of iframe itself
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
try {
// This will throw an exception if access to iframe is blocked
// due to cross-origin restrictions
styleTarget = styleTarget.contentDocument.head;
} catch(e) {
styleTarget = null;
}
}
memo[target] = styleTarget;
}

return memo[selector]
return memo[target]
};
})(function (target) {
return document.querySelector(target)
});
})();

var singleton = null;
var singletonCounter = 0;
@@ -54,10 +74,10 @@ module.exports = function(list, options) {

// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
// tags it will allow on a page
if (!options.singleton) options.singleton = isOldIE();
if (!options.singleton && typeof options.singleton !== "boolean") options.singleton = isOldIE();

// By default, add <style> tags to the <head> element
if (!options.insertInto) options.insertInto = "head";
if (!options.insertInto) options.insertInto = "head";

// By default, add <style> tags to the bottom of the target
if (!options.insertAt) options.insertAt = "bottom";
@@ -160,8 +180,11 @@ function insertStyleElement (options, style) {
stylesInsertedAtTop.push(style);
} else if (options.insertAt === "bottom") {
target.appendChild(style);
} else if (typeof options.insertAt === "object" && options.insertAt.before) {
var nextSibling = getElement(options.insertInto + " " + options.insertAt.before);
target.insertBefore(style, nextSibling);
} else {
throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");
}
}

13 changes: 11 additions & 2 deletions options.json
Original file line number Diff line number Diff line change
@@ -2,16 +2,25 @@
{
"type": "object",
"properties": {
"hmr": {
"type": "boolean"
},
"base": {
"type": "number"
},
"attrs": {
"type": "object"
},
"insertAt": {
"type": "string"
"type": ["string", "object"]
},
"insertInto": {
"anyOf": [
{ "type": "string" },
{ "instanceof": "Function" }
]
},
"transform": {
"type": "string"
},
"singleton": {
@@ -24,5 +33,5 @@
"type": "boolean"
}
},
"additionalProperties": true
"additionalProperties": false
}
6,012 changes: 6,012 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "style-loader",
"version": "0.18.2",
"version": "0.20.0",
"author": "Tobias Koppers @sokra",
"description": "style loader module for webpack",
"engines": {
@@ -15,26 +15,26 @@
"options.json"
],
"dependencies": {
"loader-utils": "^1.0.2",
"schema-utils": "^0.3.0"
"loader-utils": "^1.1.0",
"schema-utils": "^0.4.3"
},
"devDependencies": {
"css-loader": "^0.28.3",
"file-loader": "^0.11.1",
"jsdom": "^9.12.0",
"memory-fs": "^0.4.1",
"mocha": "^3.4.2",
"css-loader": "^0.28.0",
"file-loader": "^1.0.0",
"jsdom": "^9.0.0",
"memory-fs": "^0.4.0",
"mocha": "^4.0.0",
"sinon": "^4.0.0",
"standard-version": "^4.0.0",
"webpack": "^2.6.1"
"webpack": "^2.0.0"
},
"scripts": {
"test": "mocha",
"travis:test": "yarn run test",
"release": "yarn run standard-version"
},
"repository": {
"type": "git",
"url": "git@github.com:webpack/style-loader.git"
"travis:test": "npm t",
"release": "standard-version"
},
"repository": "https://github.com/webpack-contrib/style-loader.git",
"bugs": "https://github.com/webpack-contrib/style-loader/issues",
"homepage": "https://github.com/webpack-contrib/style-loader#readme",
"license": "MIT"
}
120 changes: 107 additions & 13 deletions test/basicTest.js → test/basic.test.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@ describe("basic tests", function() {
var path = require("path");

var utils = require("./utils"),
runCompilerTest = utils.runCompilerTest;
runCompilerTest = utils.runCompilerTest,
runSourceTest = utils.runSourceTest;

var fs;

@@ -19,7 +20,7 @@ describe("basic tests", function() {
}
`,
requiredStyle = `<style type="text/css">${requiredCss}</style>`,
existingStyle = "<style>.existing { color: yellow }</style>",
existingStyle = `<style id="existing-style">.existing { color: yellow }</style>`,
checkValue = '<div class="check">check</div>',
rootDir = path.resolve(__dirname + "/../") + "/",
jsdomHtml = [
@@ -31,8 +32,16 @@ describe("basic tests", function() {
"<div class='target'>",
checkValue,
"</div>",
"<iframe class='iframeTarget'/>",
"</body>",
"</html>"
].join("\n"),
requiredJS = [
"var el = document.createElement('div');",
"el.id = \"test-shadow\";",
// "var shadow = el.attachShadow({ mode: 'open' })", // sadly shadow dom not working in jsdom
"document.body.appendChild(el)",
"var css = require('./style.css');",
].join("\n");

var styleLoaderOptions = {};
@@ -59,6 +68,18 @@ describe("basic tests", function() {
}
};

var setupWebpackConfig = function() {
fs = utils.setup(webpackConfig, jsdomHtml);

// Create a tiny file system. rootDir is used because loaders are referring to absolute paths.
fs.mkdirpSync(rootDir);
fs.writeFileSync(rootDir + "main.js", requiredJS);
fs.writeFileSync(rootDir + "style.css", requiredCss);
fs.writeFileSync(rootDir + "styleTwo.css", requiredCssTwo);
fs.writeFileSync(rootDir + "localScoped.css", localScopedCss);
fs.writeFileSync(rootDir + "localComposing.css", localComposingCss);
};

beforeEach(function() {
// Reset all style-loader options
for (var member in styleLoaderOptions) {
@@ -69,15 +90,7 @@ describe("basic tests", function() {
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);
fs.writeFileSync(rootDir + "localComposing.css", localComposingCss);
setupWebpackConfig();
}); // before each

it("insert at bottom", function(done) {
@@ -94,6 +107,26 @@ describe("basic tests", function() {
runCompilerTest(expected, done);
}); // it insert at top

it("insert at before", function(done) {
styleLoaderOptions.insertAt = {
before: "#existing-style"
};

let expected = [requiredStyle, existingStyle].join("");

runCompilerTest(expected, done);
}); // it insert at before

it("insert at before invalid selector", function(done) {
styleLoaderOptions.insertAt = {
before: "#missing"
};

let expected = [existingStyle, requiredStyle].join("\n");

runCompilerTest(expected, done);
}); // it insert at before

it("insert into", function(done) {
let selector = "div.target";
styleLoaderOptions.insertInto = selector;
@@ -103,7 +136,29 @@ describe("basic tests", function() {
runCompilerTest(expected, done, undefined, selector);
}); // it insert into

it("singleton", function(done) {
it("insert into iframe", function(done) {
let selector = "iframe.iframeTarget";
styleLoaderOptions.insertInto = selector;

let expected = requiredStyle;

runCompilerTest(expected, done, function() {
return this.document.querySelector(selector).contentDocument.head.innerHTML;
}, selector);
}); // it insert into

it("insert into custom element by function", function(done) {
const selector = "#test-shadow";
styleLoaderOptions.insertInto = () => document.querySelector("#test-shadow");

let expected = requiredStyle;

runCompilerTest(expected, done, function() {
return this.document.querySelector(selector).innerHTML;
}, selector);
});

it("singleton (true)", function(done) {
// Setup
styleLoaderOptions.singleton = true;

@@ -124,6 +179,27 @@ describe("basic tests", function() {
runCompilerTest(expected, done);
}); // it singleton

it("singleton (false)", function(done) {
// Setup
styleLoaderOptions.singleton = false;

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}</style><style type="text/css">${requiredCssTwo}</style>`
].join("\n");

runCompilerTest(expected, done);
}); // it singleton

it("attrs", function(done) {
// Setup
styleLoaderOptions.attrs = {id: 'style-tag-id'};
@@ -373,7 +449,25 @@ describe("basic tests", function() {

runCompilerTest(expected, done);
});
});

describe("HMR", function() {
it("should output HMR code block by default", function(done) {
runSourceTest(/module\.hot/g, null, done);
});

it("should output HMR code block when options.hmr is true", function(done) {
styleLoaderOptions.hmr = true;
setupWebpackConfig();
runSourceTest(/module\.hot/g, null, done);
});

it("should not output HMR code block when options.hmr is false", function(done) {
styleLoaderOptions.hmr = false;
setupWebpackConfig();
runSourceTest(null, /module\.hot/g, done);
});

});

}); // describe
});
File renamed without changes.
3 changes: 3 additions & 0 deletions test/insert/into.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = function() {
return document.querySelector("#test-shadow");
};
37 changes: 37 additions & 0 deletions test/url.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Node v4 requires "use strict" to allow block scoped let & const
"use strict";

var assert = require("assert");
var sinon = require('sinon');
var loaderUtils = require('loader-utils');

var url = require("../url");

describe("url tests", function () {
var sandbox = sinon.sandbox.create();
var getOptions;

beforeEach(() => {
// Mock loaderUtils to override options
getOptions = sandbox.stub(loaderUtils, 'getOptions');
});

afterEach(() => {
sandbox.restore();
});

it("should output HMR code by default", function () {
assert.equal(/(module\.hot)/g.test(url.pitch()), true);
});

it("should NOT output HMR code when options.hmr is false", function () {
getOptions.returns({hmr: false});
assert.equal(/(module\.hot)/g.test(url.pitch()), false);
});

it("should output HMR code when options.hmr is true", function () {
getOptions.returns({hmr: true});
assert.equal(/(module\.hot)/g.test(url.pitch()), true);
});

});
37 changes: 37 additions & 0 deletions test/useable.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Node v4 requires "use strict" to allow block scoped let & const
"use strict";

var assert = require("assert");
var sinon = require('sinon');
var loaderUtils = require('loader-utils');

var useable = require("../useable");

describe("useable tests", function () {
var sandbox = sinon.sandbox.create();
var getOptions;

beforeEach(() => {
// Mock loaderUtils to override options
getOptions = sandbox.stub(loaderUtils, 'getOptions');
});

afterEach(() => {
sandbox.restore();
});

it("should output HMR code by default", function () {
assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
});

it("should NOT output HMR code when options.hmr is false", function () {
getOptions.returns({hmr: false});
assert.equal(/(module\.hot)/g.test(useable.pitch()), false);
});

it("should output HMR code when options.hmr is true", function () {
getOptions.returns({hmr: true});
assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
});

});
29 changes: 28 additions & 1 deletion test/utils.js
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ module.exports = {
virtualConsole: jsdom.createVirtualConsole().sendTo(console),
done: function(err, window) {
if (typeof actual === 'function') {
assert.equal(actual.apply(window), expected);
assert.equal(actual.apply(window), expected);
} else {
assert.equal(window.document.querySelector(selector).innerHTML.trim(), expected);
}
@@ -83,5 +83,32 @@ module.exports = {
}
});
});
},

/**
* Runs the test against Webpack compiled source code
*
* @param {RegExp} match - regex to match the source code
* @param {RegExp} noMatch - regex to NOT match the source code
* @param {Function} done - Async callback (mocha)
*/
runSourceTest: function(match, noMatch, done) {
compiler.run(function(err, stats) {
if (stats.compilation.errors.length) {
throw new Error(stats.compilation.errors);
}

const source = stats.compilation.assets["bundle.js"].source();

if (match) {
assert.equal(match.test(source), true);
}

if (noMatch) {
assert.equal(noMatch.test(source), false);
}

done();
});
}
};
25 changes: 16 additions & 9 deletions url.js
Original file line number Diff line number Diff line change
@@ -16,17 +16,24 @@ module.exports.pitch = function (request) {

validateOptions(require('./options.json'), options, 'Style Loader (URL)');

options.hmr = typeof options.hmr === 'undefined' ? true : options.hmr;

var hmr = [
// Hot Module Replacement
"if(module.hot) {",
" module.hot.accept(" + loaderUtils.stringifyRequest(this, "!!" + request) + ", function() {",
" update(require(" + loaderUtils.stringifyRequest(this, "!!" + request) + "));",
" });",
"",
" module.hot.dispose(function() { update(); });",
"}"
].join("\n");

return [
"// style-loader: Adds some reference to a css file to the DOM by adding a <link> tag",
// Adds some reference to a CSS file to the DOM by adding a <link> tag
"var update = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyleUrl.js")) + ")(",
"\trequire(" + loaderUtils.stringifyRequest(this, "!!" + request) + ")",
" require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ")",
", " + JSON.stringify(options) + ");",
"// Hot Module Replacement",
"if(module.hot) {",
"\tmodule.hot.accept(" + loaderUtils.stringifyRequest(this, "!!" + request) + ", function() {",
"\t\tupdate(require(" + loaderUtils.stringifyRequest(this, "!!" + request) + "));",
"\t});",
"\tmodule.hot.dispose(function() { update(); });",
"}"
options.hmr ? hmr : ""
].join("\n");
};
52 changes: 34 additions & 18 deletions useable.js
Original file line number Diff line number Diff line change
@@ -16,41 +16,57 @@ module.exports.pitch = function (request) {

validateOptions(require('./options.json'), options, 'Style Loader (Useable)');

return [
"var refs = 0;",
"var dispose;",
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
"if(typeof content === 'string') content = [[module.id, content, '']];",
"if(content.locals) exports.locals = content.locals;",
"exports.use = exports.ref = function() {",
" if(!(refs++)) {",
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, " + JSON.stringify(options) + ");",
" }",
" return exports;",
"};",
"exports.unuse = exports.unref = function() {",
" if(refs > 0 && !(--refs)) {",
" dispose();",
" dispose = null;",
" }",
"};",
options.hmr = typeof options.hmr === 'undefined' ? true : options.hmr;

var hmr = [
// Hot Module Replacement
"if(module.hot) {",
" var lastRefs = module.hot.data && module.hot.data.refs || 0;",
"",
" if(lastRefs) {",
" exports.ref();",
" if(!content.locals) {",
" refs = lastRefs;",
" }",
" }",
"",
" if(!content.locals) {",
" module.hot.accept();",
" }",
"",
" module.hot.dispose(function(data) {",
" data.refs = content.locals ? 0 : refs;",
"",
" if(dispose) {",
" dispose();",
" }",
" });",
"}"
].join("\n");

return [
"var refs = 0;",
"var dispose;",
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
"",
"if(typeof content === 'string') content = [[module.id, content, '']];",
// Export CSS Modules
"if(content.locals) exports.locals = content.locals;",
"",
"exports.use = exports.ref = function() {",
" if(!(refs++)) {",
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, " + JSON.stringify(options) + ");",
" }",
"",
" return exports;",
"};",
"",
"exports.unuse = exports.unref = function() {",
" if(refs > 0 && !(--refs)) {",
" dispose();",
" dispose = null;",
" }",
"};",
options.hmr ? hmr : ""
].join("\n");
};
3,164 changes: 0 additions & 3,164 deletions yarn.lock

This file was deleted.