Skip to content

Commit 5553e20

Browse files
Youcef Mammarclmath
authored andcommitted
fix issues with svg build. Fixes #29 Refs #30
1 parent 0b9c0da commit 5553e20

File tree

12 files changed

+232
-110
lines changed

12 files changed

+232
-110
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ This plugin provides an ES6 Promise implementation. If the browser does not prov
7272
See [docs/Promise.md](./docs/Promise.md) for documentation.
7373

7474
## svg
75-
This plugins provide an API for loading and bundling svg graphics.
75+
This plugin loads an svg graphic and defines it in the DOM, so you can reference it in a `<use>` tag.
7676

7777
See [docs/svg.md](./docs/svg.md) for documentation.

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"dependencies": {
66
"lie": ">=2.8",
77
"requirejs": "2.1.x",
8-
"requirejs-text": "2.0.x"
8+
"requirejs-text": "2.0.x",
9+
"requirejs-domready": "2.0.x"
910
},
1011
"devDependencies": {
1112
"jquery": ">=2.1"

docs/svg.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ title: requirejs-dplugins/svg
55

66
# requirejs-dplugins/svg!
77

8-
This plugin load svg graphics and declares them in one sprite. This sprite is automatically added to your DOM, so that you can reference included graphics in a `<use>` tag.
8+
This plugin loads an svg graphic and defines it in the DOM, so you can reference it in a `<use>` tag.
99

1010
## Example
1111

1212
```js
1313
define([
14-
"requirejs-dplugins/svg!./icon1.svg",
15-
"requirejs-dplugins/svg!./icon2.svg"
14+
"requirejs-dplugins/svg!./icon1.svg", // <svg id="icon1"...
15+
"requirejs-dplugins/svg!./icon2.svg" // <svg id="icon2"...
1616
], function(id1, id2){
1717
// id1 === "icon1" and id2 === "icon2"
1818
})
1919
```
2020

21-
This will fetch `icon1.svg` and `icon2.svg` and add two symbols to the sprite.
21+
This will fetch `icon1.svg` and `icon2.svg` and define two symbols in the DOM
2222
```svg
2323
<svg>
2424
...
@@ -27,27 +27,32 @@ This will fetch `icon1.svg` and `icon2.svg` and add two symbols to the sprite.
2727
</svg>
2828
```
2929

30-
You can then use the icons anytime only with
30+
You can then use the icons anytime with
3131

3232
```
3333
<svg>
3434
<use xlink:href="#icon1"></use>
3535
</svg>
3636
```
3737

38-
If the first `<svg>` tag of your graphic holds an `id` attribute, this id will be used as the reference. Otherwise, the name of the file is used.
38+
Note that the first `<svg>` tag of your graphic should have an `id` attribute which will be used as the reference.
39+
It should also have a `viewBox` attribute.
3940

40-
## Build
41-
The build step will merge all graphics in one sprite beforehand and save the result in a `<layer>.svg`.
42-
When running the built version, this sprite is fetched as soon as one of the graphic inside is required.
43-
44-
45-
## Creating graphics that work well with this plugin
46-
47-
To work properly, your graphic should include a `viewBox` attribute. The `id` is optional.
48-
As an example, here is the minimal markup your graphic should include:
41+
As an example, here is the minimal markup your graphic should follow:
4942

5043
```svg
5144
<svg id="my-graphic" viewBox="0 0 80 120"> ... </svg>
5245
```
5346

47+
## Build
48+
`jsdom` is used during the build step to merge all graphics in one sprite beforehand and save the result in a `<layer>.svg`.
49+
When running the built version, this sprite is fetched as soon as one of the graphics inside is required.
50+
51+
Note that `jsdom` should be added to your application `devDependencies` property in `package.json` so it is
52+
automatically installed with `npm install`.
53+
The following command will do that automatically:
54+
55+
```bash
56+
$ npm install --save-dev jsdom
57+
```
58+

samples/svg.html

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,11 @@
77

88
<script type="text/javascript">
99
require.config({
10-
baseUrl: "..",
11-
paths: {
12-
'requirejs-text': '../requirejs-text/'
13-
}
10+
baseUrl: "../.."
1411
});
1512
require([
16-
"svg!./samples/svg/add.svg",
17-
"svg!./samples/svg/download.svg"
13+
"requirejs-dplugins/svg!requirejs-dplugins/samples/svg/add.svg",
14+
"requirejs-dplugins/svg!requirejs-dplugins/samples/svg/download.svg"
1815
]);
1916
</script>
2017
</head>

svg.js

Lines changed: 97 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/**
22
* Svg loading plugin.
33
*
4-
* This plugins loads SVG files and merges them into one SVG sprite
4+
* This plugin loads an svg graphic and defines it in the DOM, so you can reference it in a `<use>` tag.
55
*
66
* @example:
77
* To load the svg file `myicons/myicon.svg`:
88
* ```
9-
* require(["requirejs-dplugins/svg!myicons/myicon.svg"], function (){
10-
* // myicon was added to the sprite
9+
* require(["requirejs-dplugins/svg!myicons/myicon.svg"], function (myiconId){
10+
* // myicon was added to the DOM
1111
* });
1212
* ```
1313
* @module requirejs-dplugins/svg
@@ -16,11 +16,14 @@
1616
define([
1717
"./has",
1818
"./Promise!",
19-
"module"
20-
], function (has, Promise, module) {
19+
"module",
20+
"require",
21+
"requirejs-text/text",
22+
"requirejs-domready/domReady"
23+
], function (has, Promise, module, localRequire, textPlugin) {
2124
"use strict";
2225

23-
var cache = {}, // paths of loaded svgs
26+
var loaded = {}, // paths of loaded svgs
2427
SPRITE_ID = 'requirejs-dplugins-svg',
2528
sprite = null;
2629

@@ -31,47 +34,43 @@ define([
3134
/**
3235
* Loads an svg file.
3336
* @param {string} path - The svg file to load.
34-
* @param {Function} require - A local require function to use to load other modules.
37+
* @param {Function} resourceRequire - A require function local to the module calling the svg plugin.
3538
* @param {Function} onload - A function to call when the specified svg file have been loaded.
3639
* @method
3740
*/
38-
load: function (path, require, onload) {
41+
load: function (path, resourceRequire, onload) {
3942
if (has("builder")) { // when building
40-
cache[path] = true;
43+
loaded[path] = true;
4144
onload();
4245
} else { // when running
43-
4446
// special case: when running a built version
4547
// Replace graphic by corresponding sprite.
48+
var idInLayer;
4649
var layersMap = module.config().layersMap;
47-
if (layersMap) {
48-
path = layersMap[path] || path;
50+
if (layersMap && layersMap[path]) {
51+
idInLayer = layersMap[path].id;
52+
path = layersMap[path].redirectTo;
4953
}
5054

51-
var filename = getFilename(path);
52-
if (path in cache) {
53-
cache[path].then(function (graphic) {
54-
onload(graphic.id);
55-
});
56-
} else {
57-
if (!sprite) {
58-
sprite = createSprite(document, SPRITE_ID);
59-
document.body.appendChild(sprite);
60-
}
61-
cache[path] = new Promise(function (resolve) {
62-
require(['requirejs-text/text!' + path], function (svgText) {
63-
var graphic = extractGraphic(document, svgText, filename),
64-
symbol = createSymbol(document, graphic.id, graphic.element, graphic.viewBox);
65-
sprite.appendChild(symbol);
66-
cache[path] = graphic.id;
67-
resolve(graphic);
55+
if (!(path in loaded)) {
56+
loaded[path] = new Promise(function (resolve) {
57+
localRequire(["requirejs-domready/domReady!"], function () {
58+
textPlugin.load(path, resourceRequire, function (svgText) {
59+
if (!sprite) {
60+
sprite = createSprite(document, SPRITE_ID);
61+
document.body.appendChild(sprite);
62+
}
63+
var symbol = extractGraphicAsSymbol(document, svgText);
64+
sprite.appendChild(symbol);
65+
resolve(symbol.getAttribute("id"));
66+
});
6867
});
6968
});
70-
71-
cache[path].then(function (graphic) {
72-
onload(graphic.id);
73-
});
7469
}
70+
71+
loaded[path].then(function (symbolId) {
72+
onload(idInLayer || symbolId);
73+
});
7574
}
7675
}
7776
};
@@ -89,8 +88,8 @@ define([
8988
* config: {
9089
* "requirejs-dplugins/svg": {
9190
* layersMap: {
92-
* "file1.svg": "path/to/layer.svg",
93-
* "file2.svg": "path/to/layer.svg"
91+
* "file1.svg": {redirectTo: "path/to/layer.svg", id: "id-inside-file-1"},
92+
* "file2.svg": {redirectTo: "path/to/layer.svg", id: "id-inside-file-2"}
9493
* }
9594
* }
9695
* }
@@ -101,19 +100,19 @@ define([
101100
* and writes it to the modules layer.
102101
* @param {string} mid - Current module id.
103102
* @param {string} dest - Current svg sprite path.
104-
* @param {Array} loadList - List of svg files contained in current sprite.
103+
* @param {Array} loaded - Maps the paths of the svg files contained in current sprite to their ids.
105104
*/
106-
writeConfig: function (write, mid, destMid, loadList) {
105+
writeConfig: function (write, mid, destMid, loaded) {
107106
var svgConf = {
108107
config: {},
109108
paths: {}
110109
};
111110
svgConf.config[mid] = {
112111
layersMap: {}
113112
};
114-
loadList.forEach(function (path) {
115-
svgConf.config[mid].layersMap[path] = destMid;
116-
});
113+
for (var path in loaded) {
114+
svgConf.config[mid].layersMap[path] = {redirectTo: destMid, id: loaded[path]};
115+
}
117116

118117
write("require.config(" + JSON.stringify(svgConf) + ");");
119118
},
@@ -124,84 +123,101 @@ define([
124123
* @param {Function} writePluginFiles - The write function provided by the builder to `writeFile`.
125124
* and writes it to the modules layer.
126125
* @param {string} dest - Current svg sprite path.
127-
* @param {Array} loadList - List of svg files contained in current sprite.
126+
* @param {Array} loaded - Maps the paths of the svg files contained in current sprite to their ids.
128127
*/
129-
writeLayer: function (writePluginFiles, dest, loadList) {
130-
var fs = require.nodeRequire("fs"),
131-
jsdom = require.nodeRequire("jsdom").jsdom;
132-
133-
var document = jsdom("<html></html>").parentWindow.document;
134-
var sprite = createSprite(document);
128+
writeLayer: function (writePluginFiles, dest, loaded) {
129+
function tryRequire(paths) {
130+
var module;
131+
var path = paths.shift();
132+
if (path) {
133+
try {
134+
// This is a node-require so it is synchronous.
135+
module = require.nodeRequire(path);
136+
} catch (e) {
137+
if (e.code === "MODULE_NOT_FOUND") {
138+
return tryRequire(paths);
139+
} else {
140+
throw e;
141+
}
142+
}
143+
}
144+
return module;
145+
}
135146

136-
loadList.forEach(function (path) {
137-
var filename = getFilename(path),
138-
svgText = fs.readFileSync(require.toUrl(path), "utf8"),
139-
graphic = extractGraphic(document, svgText, filename),
140-
symbol = createSymbol(document, graphic.id, graphic.element, graphic.viewBox);
141-
sprite.appendChild(symbol);
142-
});
147+
var fs = require.nodeRequire("fs"),
148+
jsDomPath = require.getNodePath(require.toUrl(module.id).replace(/[^\/]*$/, "node_modules/jsdom")),
149+
jsDomModule = tryRequire([jsDomPath, "jsdom"]);
150+
151+
var path, url, svgText;
152+
if (!jsDomModule) {
153+
console.log(">> WARNING: Node module jsdom not found. Skipping SVG bundling. If you" +
154+
" want SVG bundling run 'npm install jsdom' in your console.");
155+
for (path in loaded) {
156+
url = require.toUrl(path);
157+
svgText = fs.readFileSync(url, "utf8");
158+
writePluginFiles(url, svgText);
159+
}
160+
return false;
161+
} else {
162+
var jsdom = jsDomModule.jsdom,
163+
document = jsdom("<html></html>"),
164+
sprite = createSprite(document);
165+
166+
for (path in loaded) {
167+
url = require.toUrl(path);
168+
svgText = fs.readFileSync(url, "utf8");
169+
var symbol = extractGraphicAsSymbol(document, svgText);
170+
sprite.appendChild(symbol);
171+
loaded[path] = symbol.getAttribute("id");
172+
}
143173

144-
writePluginFiles(dest, sprite.outerHTML);
174+
writePluginFiles(dest, sprite.outerHTML);
175+
return true;
176+
}
145177
}
146178
};
147179

148-
149180
loadSVG.writeFile = function (pluginName, resource, require, write) {
150181
writePluginFiles = write;
151182
};
152183

153-
loadSVG.addModules = function (pluginName, resource, addModules) {
154-
addModules(["requirejs-text/text"]);
155-
};
156-
157184
loadSVG.onLayerEnd = function (write, layer) {
158185
if (layer.name && layer.path) {
159186
var dest = layer.path.replace(/^(.*\/)?(.*).js$/, "$1/$2.svg"),
160187
destMid = layer.name + ".svg";
161188

162-
var loadList = Object.keys(cache);
163-
164189
// Write layer file and config
165-
buildFunctions.writeLayer(writePluginFiles, dest, loadList);
166-
buildFunctions.writeConfig(write, module.id, destMid, loadList);
190+
var success = buildFunctions.writeLayer(writePluginFiles, dest, loaded);
191+
success && buildFunctions.writeConfig(write, module.id, destMid, loaded);
167192

168193
// Reset cache
169-
cache = {};
194+
loaded = {};
170195
}
171196
};
172197

173198
}
174199

175200
return loadSVG;
176201

177-
178-
// takes a path and returns the filename
179-
function getFilename(filepath) {
180-
return filepath.replace(/.*\/(.*)\.svg$/, "$1");
181-
}
182-
183202
// makes a symbol out of an svg graphic
184-
function extractGraphic(document, svgText, filename) {
203+
function extractGraphicAsSymbol(document, svgText) {
185204
var div = document.createElement("div");
186205
div.innerHTML = svgText;
187206
var element = div.querySelector("svg"),
188-
id = element.getAttribute("id") || filename,
189-
viewBox = element.getAttribute("viewbox") || element.getAttribute("viewBox") || "";
190-
return {
191-
id: id,
192-
viewBox: viewBox,
193-
element: element
194-
};
207+
id = element.getAttribute("id"),
208+
viewBox = element.getAttribute("viewbox") || element.getAttribute("viewBox"),
209+
symbol = createSymbol(document, id, element, viewBox);
210+
return symbol;
195211
}
196212

197213
// makes symbol from svg element
198214
function createSymbol(document, id, element, viewBox) {
199215
var symbol = document.createElementNS("http://www.w3.org/2000/svg", "symbol");
200-
symbol.setAttribute("id", id);
201216
while (element.firstChild) {
202217
symbol.appendChild(element.firstChild);
203218
}
204-
viewBox && symbol.setAttribute("viewBox", viewBox);
219+
typeof id === "string" && symbol.setAttribute("id", id);
220+
typeof viewBox === "string" && symbol.setAttribute("viewBox", viewBox);
205221
return symbol;
206222
}
207223

Lines changed: 5 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)