diff --git a/lib/build/bundled-source.js b/lib/build/bundled-source.js
index ecdacd303..fe9d89f47 100644
--- a/lib/build/bundled-source.js
+++ b/lib/build/bundled-source.js
@@ -122,14 +122,14 @@ exports.BundledSource = class {
if (path.extname(modulePath).toLowerCase() === '.json') {
// support text! prefix
- let contents = `define(\'${Utils.moduleIdWithPlugin(moduleId, 'text', loaderType)}\',[],function(){return ${JSON.stringify(this.contents)};});\n`;
+ let contents = `define('${Utils.moduleIdWithPlugin(moduleId, 'text', loaderType)}',[],function(){return ${JSON.stringify(this.contents)};});\n`;
// support Node.js's json module
- contents += `define(\'${moduleId}\',[\'${Utils.moduleIdWithPlugin(moduleId, 'text', loaderType)}\'],function(m){return JSON.parse(m);});\n`;
+ contents += `define('${moduleId}',['${Utils.moduleIdWithPlugin(moduleId, 'text', loaderType)}'],function(m){return JSON.parse(m);});\n`;
// be nice to requirejs json plugin users, add json! prefix
- contents += `define(\'${Utils.moduleIdWithPlugin(moduleId, 'json', loaderType)}\',[\'${moduleId}\'],function(m){return m;});\n`;
+ contents += `define('${Utils.moduleIdWithPlugin(moduleId, 'json', loaderType)}',['${moduleId}'],function(m){return m;});\n`;
this.contents = contents;
} else if (matchingPlugin) {
- deps = findDeps(modulePath, this.contents);
+ deps = findDeps(modulePath, this.contents, loaderType);
this.contents = matchingPlugin.transform(moduleId, modulePath, this.contents);
} else {
deps = [];
@@ -234,10 +234,28 @@ exports.BundledSource = class {
const writeTransform = allWriteTransforms(opts);
contents = writeTransform(context, moduleId, modulePath, contents);
- const tracedDeps = findDeps(modulePath, contents);
+ const tracedDeps = findDeps(modulePath, contents, loaderType);
if (tracedDeps && tracedDeps.length) {
deps.push.apply(deps, tracedDeps);
}
+ if (deps) {
+ let needsCssInjection = false;
+
+ (new Set(deps)).forEach(dep => {
+ // ignore module with plugin prefix/subfix
+ if (dep.indexOf('!') !== -1) return;
+ // only check css file
+ if (path.extname(dep).toLowerCase() !== '.css') return;
+
+ needsCssInjection = true;
+ dep = absoluteModuleId(moduleId, dep);
+ // inject css to document head
+ contents += `\ndefine('${dep}',['__inject_css__','${Utils.moduleIdWithPlugin(dep, 'text', loaderType)}'],function(i,c){i(c,'_au_css:${dep}');});\n`;
+ });
+
+ if (needsCssInjection) deps.push('__inject_css__');
+ }
+
this.contents = contents;
// write cache
diff --git a/lib/build/bundler.js b/lib/build/bundler.js
index c55e30678..d4e63af05 100644
--- a/lib/build/bundler.js
+++ b/lib/build/bundler.js
@@ -8,7 +8,7 @@ const path = require('path');
const fs = require('../file-system');
const Utils = require('./utils');
const logger = require('aurelia-logging').getLogger('Bundler');
-const stubCoreNodejsModule = require('./stub-core-nodejs-module');
+const stubModule = require('./stub-module');
exports.Bundler = class {
constructor(project, packageAnalyzer, packageInstaller) {
@@ -284,7 +284,7 @@ exports.Bundler = class {
return depInclusion.traceMain();
}
- let stub = stubCoreNodejsModule(nodeId, this.project.paths.root);
+ let stub = stubModule(nodeId, this.project.paths.root);
if (typeof stub === 'string') {
this.addFile({
path: path.resolve(this.project.paths.root, nodeId + '.js'),
@@ -300,7 +300,7 @@ exports.Bundler = class {
}
if (stub) {
- logger.info(`Auto stubbing core Node.js module: ${nodeId}`);
+ logger.info(`Auto stubbing module: ${nodeId}`);
} else {
logger.info(`Auto tracing ${description.banner}`);
}
diff --git a/lib/build/find-deps.js b/lib/build/find-deps.js
index 3297a84a5..962b99062 100644
--- a/lib/build/find-deps.js
+++ b/lib/build/find-deps.js
@@ -7,6 +7,7 @@ const astMatcher = am.astMatcher;
const htmlparser = require('htmlparser2');
const path = require('path');
const fs = require('../file-system');
+const Utils = require('./utils');
const amdNamedDefine = jsDepFinder(
'define(__dep, __any)',
@@ -158,7 +159,7 @@ const auConfigureDepFinder = function(contents) {
});
}
- return deps;
+ return Array.from(deps);
};
const inlineViewExtract = jsDepFinder(
@@ -170,7 +171,7 @@ const inlineViewExtract = jsDepFinder(
'__any.inlineView(__dep, __any)'
);
-const auInlineViewDepsFinder = function(contents) {
+const auInlineViewDepsFinder = function(contents, loaderType) {
let match = inlineViewExtract(contents);
if (match.length === 0) return [];
@@ -178,7 +179,7 @@ const auInlineViewDepsFinder = function(contents) {
// aurelia renders first inlineView without any complain.
// But this assumes there is only one custom element
// class implementation in current js file.
- return exports.findHtmlDeps('', match[0]);
+ return exports.findHtmlDeps('', match[0], loaderType);
};
// helper to add deps to a set
@@ -215,7 +216,16 @@ function isPackageName(id) {
return parts.length === 1 || (parts.length === 2 && parts[0].startsWith('@'));
}
-exports.findJsDeps = function(filename, contents) {
+function auDep(dep, loaderType) {
+ if (!dep) return dep;
+ let ext = path.extname(dep).toLowerCase();
+ if (ext === '.html' || ext === '.css') {
+ return Utils.moduleIdWithPlugin(dep, 'text', loaderType);
+ }
+ return dep;
+}
+
+exports.findJsDeps = function(filename, contents, loaderType = 'require') {
let deps = new Set();
let add = _add.bind(deps);
@@ -231,25 +241,25 @@ exports.findJsDeps = function(filename, contents) {
amdNamedDefine(parsed).forEach(d => deps.delete(d));
// aurelia dependencies PLATFORM.moduleName and some others
- add(auJsDepFinder(parsed));
+ add(auJsDepFinder(parsed).map(d => auDep(d, loaderType)));
// aurelia deps in configure func without PLATFORM.moduleName
- add(auConfigureDepFinder(parsed));
+ add(auConfigureDepFinder(parsed).map(d => auDep(d, loaderType)));
// aurelia deps in inlineView template
- add(auInlineViewDepsFinder(parsed));
+ add(auInlineViewDepsFinder(parsed, loaderType));
// aurelia view convention, try foo.html for every foo.js
let fileParts = path.parse(filename);
let htmlPair = fileParts.name + '.html';
if (fs.existsSync(fileParts.dir + path.sep + htmlPair)) {
- add('./' + htmlPair);
+ add('text!./' + htmlPair);
}
return Array.from(deps);
};
-exports.findHtmlDeps = function(filename, contents) {
+exports.findHtmlDeps = function(filename, contents, loaderType = 'require') {
let deps = new Set();
let add = _add.bind(deps);
@@ -257,15 +267,15 @@ exports.findHtmlDeps = function(filename, contents) {
onopentag: function(name, attrs) {
//
if (name === 'require' && attrs.from) {
- add(attrs.from);
+ add(auDep(attrs.from, loaderType));
//
//
} else if (name === 'compose' || attrs['as-element'] === 'compose') {
- add([attrs['view-model'], attrs.view]);
+ add([auDep(attrs['view-model'], loaderType), auDep(attrs.view, loaderType)]);
//
//
} else if (name === 'router-view' || attrs['as-element'] === 'router-view') {
- add([attrs['layout-view-model'], attrs['layout-view']]);
+ add([auDep(attrs['layout-view-model'], loaderType), auDep(attrs['layout-view'], loaderType)]);
}
}
});
@@ -275,13 +285,13 @@ exports.findHtmlDeps = function(filename, contents) {
return Array.from(deps);
};
-exports.findDeps = function(filename, contents) {
+exports.findDeps = function(filename, contents, loaderType = 'require') {
let ext = path.extname(filename).toLowerCase();
if (ext === '.js') {
- return exports.findJsDeps(filename, contents);
+ return exports.findJsDeps(filename, contents, loaderType);
} else if (ext === '.html' || ext === '.htm') {
- return exports.findHtmlDeps(filename, contents);
+ return exports.findHtmlDeps(filename, contents, loaderType);
}
return [];
diff --git a/lib/build/inject-css.js b/lib/build/inject-css.js
new file mode 100644
index 000000000..d3aa1462e
--- /dev/null
+++ b/lib/build/inject-css.js
@@ -0,0 +1,79 @@
+'use strict';
+let cssUrlMatcher = /url\s*\(\s*(?!['"]data)([^) ]+)\s*\)/gi;
+
+// copied from aurelia-templating-resources css-resource
+// This behaves differently from webpack's style-loader.
+// Here we change './hello.png' to 'foo/hello.png' if base address is 'foo/bar'.
+// Note 'foo/hello.png' is technically a relative path in css,
+// this is designed to work with aurelia-router setup.
+// We inject css into a style tag on html head, it means the 'foo/hello.png'
+// is related to current url (not css url on link tag), or tag in html
+// head (which is recommended setup of router if not using hash).
+function fixupCSSUrls(address, css) {
+ if (typeof css !== 'string') {
+ throw new Error(`Failed loading required CSS file: ${address}`);
+ }
+ return css.replace(cssUrlMatcher, (match, p1) => {
+ let quote = p1.charAt(0);
+ if (quote === '\'' || quote === '"') {
+ p1 = p1.substr(1, p1.length - 2);
+ }
+ const absolutePath = absoluteModuleId(address, p1);
+ if (absolutePath === p1) {
+ return match;
+ }
+ return 'url(\'' + absolutePath + '\')';
+ });
+}
+
+function absoluteModuleId(baseId, moduleId) {
+ if (moduleId[0] !== '.') return moduleId;
+
+ let parts = baseId.split('/');
+ parts.pop();
+
+ moduleId.split('/').forEach(p => {
+ if (p === '.') return;
+ if (p === '..') {
+ parts.pop();
+ return;
+ }
+ parts.push(p);
+ });
+
+ return parts.join('/');
+}
+
+// copied from aurelia-pal-browser DOM.injectStyles
+function injectCSS(css, id) {
+ if (typeof document === 'undefined' || !css) return;
+ css = fixupCSSUrls(id, css);
+
+ if (id) {
+ let oldStyle = document.getElementById(id);
+ if (oldStyle) {
+ let isStyleTag = oldStyle.tagName.toLowerCase() === 'style';
+
+ if (isStyleTag) {
+ oldStyle.innerHTML = css;
+ return;
+ }
+
+ throw new Error('The provided id does not indicate a style tag.');
+ }
+ }
+
+ let node = document.createElement('style');
+ node.innerHTML = css;
+ node.type = 'text/css';
+
+ if (id) {
+ node.id = id;
+ }
+
+ document.head.appendChild(node);
+}
+
+injectCSS.fixupCSSUrls = fixupCSSUrls;
+
+module.exports = injectCSS;
diff --git a/lib/build/stub-core-nodejs-module.js b/lib/build/stub-module.js
similarity index 92%
rename from lib/build/stub-core-nodejs-module.js
rename to lib/build/stub-module.js
index ff7f544c3..6d46dcdf6 100644
--- a/lib/build/stub-core-nodejs-module.js
+++ b/lib/build/stub-module.js
@@ -14,7 +14,7 @@ const logger = require('aurelia-logging').getLogger('StubNodejs');
// process
// string_decoder
// url
-// util (note: got small problem on ./support/isBuffer, read util package.json browser field)
+// util
// fail on following core modules has no stub
const UNAVAIABLE_CORE_MODULES = [
@@ -75,5 +75,13 @@ module.exports = function(moduleId, root) {
if (moduleId === '__ignore__') {
return EMPTY_MODULE;
}
+
+ if (moduleId === '__inject_css__') {
+ return {
+ name: '__inject_css__',
+ path: resolvePath('aurelia-cli', root),
+ main: 'lib/build/inject-css'
+ };
+ }
};
diff --git a/spec/lib/build/bundled-source.spec.js b/spec/lib/build/bundled-source.spec.js
index d428504bb..611a77177 100644
--- a/spec/lib/build/bundled-source.spec.js
+++ b/spec/lib/build/bundled-source.spec.js
@@ -126,6 +126,55 @@ describe('the BundledSource module', () => {
expect(bundler.configTargetBundle.addAlias).toHaveBeenCalledWith('b8/loo', 'foo/bar/loo');
});
+ it('transforms local js file with css injection', () => {
+ let file = {
+ path: path.resolve(cwd, 'src/foo.js'),
+ contents: "define(['./foo.css', 'bar'], function(c,b){});"
+ };
+
+ let bs = new BundledSource(bundler, file);
+ bs._getProjectRoot = () => 'src';
+ bs._getLoaderPlugins = () => [];
+ bs._getLoaderConfig = () => ({
+ paths: {
+ root: 'src',
+ resources: 'resources'
+ }
+ });
+ bs._getUseCache = () => undefined;
+
+ let deps = bs.transform();
+ expect(deps).toEqual(['bar', '__inject_css__']); // relative dep is ignored
+ expect(bs.requiresTransform).toBe(false);
+ expect(bs.contents).toBe(`define('foo',['./foo.css', 'bar'], function(c,b){});
+define('foo.css',['__inject_css__','text!foo.css'],function(i,c){i(c,'_au_css:foo.css');});
+`);
+ });
+
+ it('transforms local js file with inlineView with css dep', () => {
+ let file = {
+ path: path.resolve(cwd, 'src/foo.js'),
+ contents: 'define([\'au\'], function(au){au.inlineView(\'\', [\'bar.css\', \'./a.css\']);});'
+ };
+
+ let bs = new BundledSource(bundler, file);
+ bs._getProjectRoot = () => 'src';
+ bs._getLoaderPlugins = () => [];
+ bs._getLoaderConfig = () => ({
+ paths: {
+ root: 'src',
+ resources: 'resources'
+ }
+ });
+ bs._getUseCache = () => undefined;
+
+ let deps = bs.transform();
+ expect(deps).toEqual(['au', 'bar.css', 'foo.css']); // relative dep is ignored, text! prefix is stripped
+ expect(bs.requiresTransform).toBe(false);
+ // doesn't call DOM.injectStyles for inlineView css
+ expect(bs.contents).toBe('define(\'foo\',[\'au\'], function(au){au.inlineView(\'\', [\'bar.css\', \'./a.css\']);});');
+ });
+
it('transforms local js file above root level (src/)', () => {
let file = {
path: path.resolve(cwd, '../shared/bar/loo.js'),
diff --git a/spec/lib/build/find-deps.spec.js b/spec/lib/build/find-deps.spec.js
index 083380a95..8c1c4e9db 100644
--- a/spec/lib/build/find-deps.spec.js
+++ b/spec/lib/build/find-deps.spec.js
@@ -43,7 +43,7 @@ let html = `
`;
-let htmlDeps = ['./c.html', 'a/b', 'd/e.css', 'lv1', 'lv2', 'lvm2', 'v2', 'vm1', 'vm2'];
+let htmlDeps = ['a/b', 'lv1', 'lv2', 'lvm2', 'text!./c.html', 'text!d/e.css', 'v2', 'vm1', 'vm2'];
let css = `
@import 'other.css';
@@ -229,7 +229,7 @@ describe('find-deps', () => {
_classCallCheck(this, MyComp);
}) || _class);
`;
- expect(findJsDeps('my-comp.js', file).sort()).toEqual(['./b.css', 'a.css']);
+ expect(findJsDeps('my-comp.js', file).sort()).toEqual(['text!./b.css', 'text!a.css']);
});
it('find deps on useView', () => {
@@ -252,7 +252,7 @@ describe('find-deps', () => {
_classCallCheck(this, MyComp);
}) || _class);
`;
- expect(findJsDeps('my-comp.js', file)).toEqual(['./a.html']);
+ expect(findJsDeps('my-comp.js', file, 'system')).toEqual(['./a.html!text']);
});
it('find deps in inlineView html', () => {
@@ -274,7 +274,7 @@ describe('find-deps', () => {
_classCallCheck(this, MyComp);
}) || _class);
`;
- expect(findJsDeps('my-comp.js', file)).toEqual(['./a.css']);
+ expect(findJsDeps('my-comp.js', file)).toEqual(['text!./a.css']);
});
it('find deps in inlineView html for TypeScript compiled code', () => {
@@ -303,7 +303,7 @@ var MyComp = (function () {
})();
exports.MyComp = MyComp;
`;
- expect(findJsDeps('my-comp.js', file)).toEqual(['./a.css']);
+ expect(findJsDeps('my-comp.js', file)).toEqual(['text!./a.css']);
});
it('find deps in inlineView html, and additional deps', () => {
@@ -327,15 +327,15 @@ exports.MyComp = MyComp;
_classCallCheck(this, MyComp);
}) || _class);
`;
- expect(findJsDeps('my-comp.js', file).sort()).toEqual(['./a.css', './b.css', './c.css']);
+ expect(findJsDeps('my-comp.js', file).sort()).toEqual(['text!./a.css', 'text!./b.css', 'text!./c.css']);
});
it('find html file by aurelia view convention', () => {
const fsConfig = {};
fsConfig['src/foo.html'] = 'contents';
mockfs(fsConfig);
- expect(findJsDeps('src/foo.js', 'a();')).toEqual(['./foo.html']);
- expect(findDeps('src/foo.js', 'a();')).toEqual(['./foo.html']);
+ expect(findJsDeps('src/foo.js', 'a();')).toEqual(['text!./foo.html']);
+ expect(findDeps('src/foo.js', 'a();')).toEqual(['text!./foo.html']);
});
it('remove inner defined modules', () => {
diff --git a/spec/lib/build/inject-css.spec.js b/spec/lib/build/inject-css.spec.js
new file mode 100644
index 000000000..72b6bc2f8
--- /dev/null
+++ b/spec/lib/build/inject-css.spec.js
@@ -0,0 +1,141 @@
+'use strict';
+const fixupCSSUrls = require('../../../lib/build/inject-css').fixupCSSUrls;
+
+// tests partly copied from
+// https://github.com/webpack-contrib/style-loader/blob/master/test/fixUrls.test.js
+describe('fixupCSSUrls', () => {
+ it('throws on null/undefined', () => {
+ expect(() => fixupCSSUrls('foo/bar', null)).toThrow();
+ expect(() => fixupCSSUrls('foo/bar', undefined)).toThrow();
+ });
+
+ it('Blank css is not modified', () => {
+ const css = '';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it('No url is not modified', () => {
+ const css = 'body { }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (no quotes)", () => {
+ const css = 'body { background-image:url ( http://example.com/bg.jpg ); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (no quotes, spaces)", () => {
+ const css = 'body { background-image:url ( http://example.com/bg.jpg ); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (double quotes)", () => {
+ const css = 'body { background-image:url(\"http://example.com/bg.jpg\"); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (double quotes, spaces)", () => {
+ const css = 'body { background-image:url ( \"http://example.com/bg.jpg\" ); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (single quotes)", () => {
+ const css = 'body { background-image:url(\'http://example.com/bg.jpg\'); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Full url isn't changed (single quotes, spaces)", () => {
+ const css = 'body { background-image:url ( \'http://example.com/bg.jpg\' ); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it('Multiple full urls are not changed', () => {
+ const css = "body { background-image:url(http://example.com/bg.jpg); }\ndiv.main { background-image:url ( 'https://www.anothersite.com/another.png' ); }";
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Http url isn't changed", function() {
+ const css = 'body { background-image:url(http://example.com/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Https url isn't changed", function() {
+ const css = 'body { background-image:url(https://example.com/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("HTTPS url isn't changed", function() {
+ const css = 'body { background-image:url(HTTPS://example.com/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("File url isn't changed", function() {
+ const css = 'body { background-image:url(file:///example.com/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Double slash url isn't changed", function() {
+ const css = 'body { background-image:url(//example.com/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Image data uri url isn't changed", function() {
+ const css = 'body { background-image:url(data:image/png;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg==); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Font data uri url isn't changed", function() {
+ const css = 'body { background-image:url(data:application/x-font-woff;charset=utf-8;base64,qsrwABYuwNkimqm3gAAAABJRU5ErkJggg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it('Relative url with dot slash', function() {
+ const css = 'body { background-image:url(./c/d/bg.jpg); }';
+ const expected = "body { background-image:url('foo/c/d/bg.jpg'); }";
+ expect(fixupCSSUrls('foo/bar', css)).toBe(expected);
+ });
+
+ it('Multiple relative urls', function() {
+ const css = 'body { background-image:URL ( "./bg.jpg" ); }\ndiv.main { background-image:url(../c/d/bg.jpg); }';
+ const expected = "body { background-image:url('foo/bg.jpg'); }\ndiv.main { background-image:url('c/d/bg.jpg'); }";
+ expect(fixupCSSUrls('foo/bar', css)).toBe(expected);
+ });
+
+ it("url with hash isn't changed", function() {
+ const css = 'body { background-image:url(#bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it('Empty url should be skipped', function() {
+ let css = 'body { background-image:url(); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url( ); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(\n); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(\'\'); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(\' \'); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(""); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(" "); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Rooted url isn't changed", function() {
+ let css = 'body { background-image:url(/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ css = 'body { background-image:url(/a/b/bg.jpg); }';
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+
+ it("Doesn't break inline SVG", function() {
+ const css = "body { background-image:url('data:image/svg+xml;charset=utf-8,'); }";
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+ it("Doesn't break inline SVG with HTML comment", function() {
+ const css = "body { background-image:url('data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%3C!--%20Comment%20--%3E%0A%3Csvg%3E%3C%2Fsvg%3E%0A'); }";
+ expect(fixupCSSUrls('foo/bar', css)).toBe(css);
+ });
+});
diff --git a/spec/lib/build/stub-core-nodejs-module.spec.js b/spec/lib/build/stub-module.spec.js
similarity index 51%
rename from spec/lib/build/stub-core-nodejs-module.spec.js
rename to spec/lib/build/stub-module.spec.js
index 4dbcc13c1..96878df99 100644
--- a/spec/lib/build/stub-core-nodejs-module.spec.js
+++ b/spec/lib/build/stub-module.spec.js
@@ -1,19 +1,19 @@
'use strict';
-const stubCoreNodejsModule = require('../../../lib/build/stub-core-nodejs-module');
+const stubModule = require('../../../lib/build/stub-module');
describe('StubCoreNodejsModule', () => {
it('stubs some core module with subfix -browserify', () => {
- expect(stubCoreNodejsModule('os', 'src')).toEqual({
+ expect(stubModule('os', 'src')).toEqual({
name: 'os',
path: '../node_modules/os-browserify'
});
});
it('ignores sys', () => {
- expect(stubCoreNodejsModule('sys', 'src')).toBeUndefined();
+ expect(stubModule('sys', 'src')).toBeUndefined();
});
it('stubs empty module for some core module', () => {
- expect(stubCoreNodejsModule('fs', 'src')).toBe('define(function(){});');
+ expect(stubModule('fs', 'src')).toBe('define(function(){});');
});
});