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: 6ca2ecbff75703ccd679ef2b176eac9c5141f52a
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
  • 11 commits
  • 17 files changed
  • 5 contributors

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,228 additions and 3,313 deletions.
  1. +6 −6 .travis.yml
  2. +18 −0 CHANGELOG.md
  3. +16 −3 README.md
  4. +62 −20 index.js
  5. +20 −10 lib/addStyles.js
  6. +7 −1 options.json
  7. +6,012 −0 package-lock.json
  8. +15 −16 package.json
  9. +24 −7 test/{basicTest.js → basic.test.js}
  10. 0 test/{fixUrlsTest.js → fixUrls.test.js}
  11. +3 −0 test/insert/into.js
  12. +3 −3 test/{urlTest.js → url.test.js}
  13. +3 −3 test/{useableTest.js → useable.test.js}
  14. +13 −11 test/utils.js
  15. +10 −9 url.js
  16. +16 −7 useable.js
  17. +0 −3,217 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)
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,24 @@

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)

19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -139,7 +139,7 @@ Styles are not added on `import/require()`, but instead on call to `use`/`ref`.
|**`attrs`**|`{Object}`|`{}`|Add custom attrs to `<style></style>`|
|**`transform`** |`{Function}`|`false`|Transform/Conditionally load CSS by passing a transform/condition function|
|**`insertAt`**|`{String\|Object}`|`bottom`|Inserts `<style></style>` at the given position|
|**`insertInto`**|`{String}`|`<head>`|Inserts `<style></style>` into 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`|Converts relative URLs to absolute urls, when source maps are enabled|
@@ -318,14 +318,27 @@ A new `<style>` element can be inserted before a specific element by passing an

### `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 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 insert the styles into a [ShadowRoot](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot), e.g

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',
options: {
insertInto: '#host::shadow>#root'
insertInto: () => document.querySelector("#root").shadowRoot,
}
}
```
82 changes: 62 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,39 +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;

var hmrCode = [
"// Hot Module Replacement",
// 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",
" 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",
// 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;",
options.hmr ? hmrCode : ""
"",
options.hmr ? hmr : ""
].join("\n");
};
30 changes: 20 additions & 10 deletions lib/addStyles.js
Original file line number Diff line number Diff line change
@@ -23,14 +23,26 @@ 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") {
var styleTarget = 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 (styleTarget instanceof window.HTMLIFrameElement) {
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
try {
// This will throw an exception if access to iframe is blocked
// due to cross-origin restrictions
@@ -39,13 +51,11 @@ var getElement = (function (fn) {
styleTarget = null;
}
}
memo[selector] = styleTarget;
memo[target] = styleTarget;
}
return memo[selector]
return memo[target]
};
})(function (target) {
return document.querySelector(target)
});
})();

var singleton = null;
var singletonCounter = 0;
@@ -67,7 +77,7 @@ module.exports = function(list, options) {
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";
8 changes: 7 additions & 1 deletion options.json
Original file line number Diff line number Diff line change
@@ -15,6 +15,12 @@
"type": ["string", "object"]
},
"insertInto": {
"anyOf": [
{ "type": "string" },
{ "instanceof": "Function" }
]
},
"transform": {
"type": "string"
},
"singleton": {
@@ -27,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.

31 changes: 15 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "style-loader",
"version": "0.19.1",
"version": "0.20.0",
"author": "Tobias Koppers @sokra",
"description": "style loader module for webpack",
"engines": {
@@ -15,27 +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",
"sinon": "^2.4.1",
"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"
}
31 changes: 24 additions & 7 deletions test/basicTest.js → test/basic.test.js
Original file line number Diff line number Diff line change
@@ -35,6 +35,13 @@ describe("basic tests", function() {
"<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 = {};
@@ -66,7 +73,7 @@ describe("basic tests", function() {

// Create a tiny file system. rootDir is used because loaders are referring to absolute paths.
fs.mkdirpSync(rootDir);
fs.writeFileSync(rootDir + "main.js", "var css = require('./style.css');");
fs.writeFileSync(rootDir + "main.js", requiredJS);
fs.writeFileSync(rootDir + "style.css", requiredCss);
fs.writeFileSync(rootDir + "styleTwo.css", requiredCssTwo);
fs.writeFileSync(rootDir + "localScoped.css", localScopedCss);
@@ -140,6 +147,17 @@ describe("basic tests", function() {
}, 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;
@@ -433,24 +451,23 @@ describe("basic tests", function() {
});
});

describe("hmr option", function() {

describe("HMR", function() {
it("should output HMR code block by default", function(done) {
runSourceTest(/Hot Module Replacement/g, null, 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(/Hot Module Replacement/g, null, done);
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, /Hot Module Replacement/g, done);
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");
};
6 changes: 3 additions & 3 deletions test/urlTest.js → test/url.test.js
Original file line number Diff line number Diff line change
@@ -21,17 +21,17 @@ describe("url tests", function () {
});

it("should output HMR code by default", function () {
assert.equal(/Hot Module Replacement/g.test(url.pitch()), true);
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(/Hot Module Replacement/g.test(url.pitch()), 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(/Hot Module Replacement/g.test(url.pitch()), true);
assert.equal(/(module\.hot)/g.test(url.pitch()), true);
});

});
6 changes: 3 additions & 3 deletions test/useableTest.js → test/useable.test.js
Original file line number Diff line number Diff line change
@@ -21,17 +21,17 @@ describe("useable tests", function () {
});

it("should output HMR code by default", function () {
assert.equal(/Hot Module Replacement/g.test(useable.pitch()), true);
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(/Hot Module Replacement/g.test(useable.pitch()), 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(/Hot Module Replacement/g.test(useable.pitch()), true);
assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
});

});
24 changes: 13 additions & 11 deletions test/utils.js
Original file line number Diff line number Diff line change
@@ -85,25 +85,27 @@ module.exports = {
});
},

/*
* Runs the test against Webpack compiled source code.
* @param {regex} regexToMatch - regex to match the source code
* @param {regex} regexToNotMatch - regex to NOT match the source code
* @param {function} done - Async callback from Mocha.
/**
* 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(regexToMatch, regexToNotMatch, done) {
runSourceTest: function(match, noMatch, done) {
compiler.run(function(err, stats) {
if (stats.compilation.errors.length) {
throw new Error(stats.compilation.errors);
}

const bundleJs = stats.compilation.assets["bundle.js"].source();
if (regexToMatch) {
assert.equal(regexToMatch.test(bundleJs), true);
const source = stats.compilation.assets["bundle.js"].source();

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

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

done();
19 changes: 10 additions & 9 deletions url.js
Original file line number Diff line number Diff line change
@@ -18,21 +18,22 @@ module.exports.pitch = function (request) {

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

var hmrCode = [
"// Hot Module Replacement",
var hmr = [
// 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(); });",
" 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) + ");",
options.hmr ? hmrCode : ""
options.hmr ? hmr : ""
].join("\n");
};
23 changes: 16 additions & 7 deletions useable.js
Original file line number Diff line number Diff line change
@@ -18,21 +18,25 @@ module.exports.pitch = function (request) {

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

var hmrCode = [
"// Hot Module Replacement",
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();",
" }",
@@ -44,20 +48,25 @@ module.exports.pitch = function (request) {
"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;",
" }",
" if(refs > 0 && !(--refs)) {",
" dispose();",
" dispose = null;",
" }",
"};",
options.hmr ? hmrCode : ""
options.hmr ? hmr : ""
].join("\n");
};
3,217 changes: 0 additions & 3,217 deletions yarn.lock

This file was deleted.