Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(useable): add insertInto support (options.insertInto) #341

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 124 additions & 18 deletions test/useable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,136 @@ var loaderUtils = require('loader-utils');
var useable = require("../useable");

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

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

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

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

it("should output HMR code when options.hmr is true", function () {
getOptions.returns({hmr: true});
assert.equal(/(module\.hot)/g.test(useable.pitch()), true);
describe('insert into', 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; }",
localComposingCss = `
:local(.composingClass) {
composes: className from './localScoped.css';
color: blue;
}
`,
requiredStyle = `<style type="text/css">${requiredCss}</style>`,
existingStyle = `<style id="existing-style">.existing { color: yellow }</style>`,
checkValue = '<div class="check">check</div>',
rootDir = path.resolve(__dirname + "/../") + "/",
jsdomHtml = [
"<html>",
"<head id='head'>",
existingStyle,
"</head>",
"<body>",
"<div class='target'>",
checkValue,
"</div>",
"<iframe class='iframeTarget'/>",
"</body>",
"</html>"
].join("\n"),
requiredJS = [
"var el = document.createElement('div');",
"el.id = \"test-shadow\";",
"document.body.appendChild(el)",
"var css = require('./style.css');",
"css.use();",
].join("\n");

var styleLoaderOptions = {};
var cssRule = {};

var defaultCssRule = {
test: /\.css?$/,
use: [
{
loader: "style-loader/useable",
options: styleLoaderOptions
},
"css-loader"
]
};

var webpackConfig = {
entry: "./main.js",
output: {
filename: "bundle.js"
},
module: {
rules: [cssRule]
}
};

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) {
delete styleLoaderOptions[member];
}

for (var member in defaultCssRule) {
cssRule[member] = defaultCssRule[member];
}

setupWebpackConfig();
}); // before each

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

});

});
19 changes: 18 additions & 1 deletion useable.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ module.exports.pitch = function (request) {

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) {",
Expand Down Expand Up @@ -48,14 +63,16 @@ module.exports.pitch = function (request) {
"var refs = 0;",
"var dispose;",
"var content = require(" + loaderUtils.stringifyRequest(this, "!!" + request) + ");",
"var options = " + JSON.stringify(options) + ";",
"options.insertInto = " + insertInto + ";",
"",
"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) + ");",
" dispose = require(" + loaderUtils.stringifyRequest(this, "!" + path.join(__dirname, "lib", "addStyles.js")) + ")(content, options);",
" }",
"",
" return exports;",
Expand Down