UNPKG

5.83 kBJavaScriptView Raw
1const fs = require('fs');
2const path = require('path');
3const _ = require('lodash');
4const Funnel = require('broccoli-funnel');
5const MergeTrees = require('broccoli-merge-trees');
6const SVGOptimizer = require('broccoli-svg-optimizer');
7const Symbolizer = require('broccoli-symbolizer');
8const InlinePacker = require('./inline-packer');
9const ViewerAssetsBuilder = require('./viewer-assets-builder');
10const ViewerBuilder = require('./viewer-builder');
11const validateOptions = require('./validate-options');
12const defaultGenerators = require('./default-generators');
13
14// GLOBAL_OPTIONS can be defined as both a root or strategy specific option.
15const GLOBAL_OPTIONS = ['sourceDirs', 'stripPath', 'optimizer'];
16
17const symbolsLoaderScript = fs.readFileSync(
18 path.join(__dirname, '../symbols-loader.html'), 'utf8'
19);
20
21function mergeTreesIfNeeded(trees, options) {
22 return trees.length === 1 ? trees[0] : new MergeTrees(trees, options);
23}
24
25module.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 // see: https://github.com/ember-cli/ember-cli/issues/3718
36 if (typeof app.import !== 'function' && app.app) {
37 // eslint-disable-next-line no-param-reassign
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};