1 | const fs = require('fs');
|
2 | const path = require('path');
|
3 | const _ = require('lodash');
|
4 | const Funnel = require('broccoli-funnel');
|
5 | const MergeTrees = require('broccoli-merge-trees');
|
6 | const SVGOptimizer = require('broccoli-svg-optimizer');
|
7 | const Symbolizer = require('broccoli-symbolizer');
|
8 | const InlinePacker = require('./inline-packer');
|
9 | const ViewerAssetsBuilder = require('./viewer-assets-builder');
|
10 | const ViewerBuilder = require('./viewer-builder');
|
11 | const validateOptions = require('./validate-options');
|
12 | const defaultGenerators = require('./default-generators');
|
13 |
|
14 |
|
15 | const GLOBAL_OPTIONS = ['sourceDirs', 'stripPath', 'optimizer'];
|
16 |
|
17 | const symbolsLoaderScript = fs.readFileSync(
|
18 | path.join(__dirname, '../symbols-loader.html'), 'utf8'
|
19 | );
|
20 |
|
21 | function mergeTreesIfNeeded(trees, options) {
|
22 | return trees.length === 1 ? trees[0] : new MergeTrees(trees, options);
|
23 | }
|
24 |
|
25 | module.exports = {
|
26 | name: 'ember-svg-jar',
|
27 |
|
28 | isDevelopingAddon() {
|
29 | return false;
|
30 | },
|
31 |
|
32 | included(app) {
|
33 | this._super.included.apply(this, arguments);
|
34 |
|
35 |
|
36 | if (typeof app.import !== 'function' && app.app) {
|
37 |
|
38 | app = app.app;
|
39 | }
|
40 |
|
41 | this.initializeOptions(app.options.svgJar, app.env);
|
42 | },
|
43 |
|
44 | treeForPublic() {
|
45 | let trees = [];
|
46 |
|
47 | if (this.options.viewer.enabled) {
|
48 | trees.push(this.getViewerTree());
|
49 |
|
50 | if (this.options.viewer.embed) {
|
51 | trees.push(this._super.treeForPublic.apply(this, arguments));
|
52 | }
|
53 | }
|
54 |
|
55 | if (this.hasSymbolStrategy()) {
|
56 | trees.push(this.getSymbolStrategyTree());
|
57 | }
|
58 |
|
59 | return mergeTreesIfNeeded(trees);
|
60 | },
|
61 |
|
62 | treeForApp(appTree) {
|
63 | let trees = [appTree];
|
64 |
|
65 | if (this.hasInlineStrategy()) {
|
66 | trees.push(this.getInlineStrategyTree());
|
67 | }
|
68 |
|
69 | return mergeTreesIfNeeded(trees, { overwrite: true });
|
70 | },
|
71 |
|
72 | contentFor(type) {
|
73 | let includeLoader =
|
74 | this.hasSymbolStrategy() && this.optionFor('symbol', 'includeLoader');
|
75 |
|
76 | if (type === 'body' && includeLoader) {
|
77 | return symbolsLoaderScript
|
78 | .replace('{{FILE_PATH}}', this.optionFor('symbol', 'outputFile'));
|
79 | }
|
80 |
|
81 | return '';
|
82 | },
|
83 |
|
84 | initializeOptions(options, env) {
|
85 | this.options = _.merge({
|
86 | sourceDirs: ['public'],
|
87 | strategy: 'inline',
|
88 | stripPath: true,
|
89 | optimizer: {},
|
90 | persist: true,
|
91 |
|
92 | viewer: {
|
93 | enabled: env === 'development',
|
94 | embed: env === 'development'
|
95 | },
|
96 |
|
97 | inline: {
|
98 | idGen: defaultGenerators.inlineIdGen,
|
99 | copypastaGen: defaultGenerators.inlineCopypastaGen
|
100 | },
|
101 |
|
102 | symbol: {
|
103 | idGen: defaultGenerators.symbolIdGen,
|
104 | copypastaGen: defaultGenerators.symbolCopypastaGen,
|
105 | outputFile: '/assets/symbols.svg',
|
106 | prefix: '',
|
107 | includeLoader: true
|
108 | }
|
109 | }, options || {});
|
110 |
|
111 | validateOptions(this.options);
|
112 | this.options.strategy = _.castArray(this.options.strategy);
|
113 | },
|
114 |
|
115 | optionFor(strategy, optionName) {
|
116 | return _.isUndefined(this.options[strategy][optionName])
|
117 | ? GLOBAL_OPTIONS.indexOf(optionName) !== -1 && this.options[optionName]
|
118 | : this.options[strategy][optionName];
|
119 | },
|
120 |
|
121 | sourceDirsFor(strategy) {
|
122 | return this.optionFor(strategy, 'sourceDirs')
|
123 | .filter((sourceDir) => fs.existsSync(sourceDir));
|
124 | },
|
125 |
|
126 | svgFilesFor(strategy) {
|
127 | this.svgFilesCache = this.svgFilesCache || {};
|
128 |
|
129 | if (this.svgFilesCache[strategy]) {
|
130 | return this.svgFilesCache[strategy];
|
131 | }
|
132 |
|
133 | let sourceDirs = this.sourceDirsFor(strategy);
|
134 | let svgFiles = new Funnel(mergeTreesIfNeeded(sourceDirs), {
|
135 | include: ['**/*.svg']
|
136 | });
|
137 |
|
138 | let svgoConfig = this.optionFor(strategy, 'optimizer');
|
139 | if (svgoConfig) {
|
140 | svgFiles = new SVGOptimizer(svgFiles, {
|
141 | svgoConfig,
|
142 | persist: this.options.persist
|
143 | });
|
144 | }
|
145 |
|
146 | this.svgFilesCache[strategy] = svgFiles;
|
147 |
|
148 | return svgFiles;
|
149 | },
|
150 |
|
151 | originalSvgFilesFor(strategy) {
|
152 | let sourceDirs = this.sourceDirsFor(strategy);
|
153 |
|
154 | return new Funnel(mergeTreesIfNeeded(sourceDirs), {
|
155 | include: ['**/*.svg'],
|
156 | destDir: '__original__'
|
157 | });
|
158 | },
|
159 |
|
160 | getViewerTree() {
|
161 | let idGenOpts = {
|
162 | symbol: {
|
163 | prefix: this.optionFor('symbol', 'prefix')
|
164 | }
|
165 | };
|
166 |
|
167 | let viewerBuilderNodes = this.options.strategy.map((strategy) => {
|
168 | let inputNode = new MergeTrees([
|
169 | this.svgFilesFor(strategy),
|
170 | this.originalSvgFilesFor(strategy)
|
171 | ]);
|
172 |
|
173 | return new ViewerAssetsBuilder(inputNode, {
|
174 | strategy,
|
175 | idGen: this.optionFor(strategy, 'idGen'),
|
176 | idGenOpts: idGenOpts[strategy],
|
177 | copypastaGen: this.optionFor(strategy, 'copypastaGen'),
|
178 | stripPath: this.optionFor(strategy, 'stripPath'),
|
179 | outputFile: `${strategy}.json`,
|
180 | ui: this.ui
|
181 | });
|
182 | });
|
183 |
|
184 | return new ViewerBuilder(mergeTreesIfNeeded(viewerBuilderNodes), {
|
185 | outputFile: 'svg-jar.json',
|
186 | hasManyStrategies: this.options.strategy.length > 1
|
187 | });
|
188 | },
|
189 |
|
190 | getInlineStrategyTree() {
|
191 | return new InlinePacker(this.svgFilesFor('inline'), {
|
192 | idGen: this.optionFor('inline', 'idGen'),
|
193 | stripPath: this.optionFor('inline', 'stripPath'),
|
194 | outputFile: 'inline-assets.js'
|
195 | });
|
196 | },
|
197 |
|
198 | getSymbolStrategyTree() {
|
199 | return new Symbolizer(this.svgFilesFor('symbol'), {
|
200 | idGen: this.optionFor('symbol', 'idGen'),
|
201 | stripPath: this.optionFor('symbol', 'stripPath'),
|
202 | outputFile: this.optionFor('symbol', 'outputFile'),
|
203 | prefix: this.optionFor('symbol', 'prefix'),
|
204 | persist: this.options.persist
|
205 | });
|
206 | },
|
207 |
|
208 | hasInlineStrategy() {
|
209 | return this.options.strategy.indexOf('inline') !== -1;
|
210 | },
|
211 |
|
212 | hasSymbolStrategy() {
|
213 | return this.options.strategy.indexOf('symbol') !== -1;
|
214 | }
|
215 | };
|