UNPKG

5.11 kBJavaScriptView Raw
1'use strict';
2
3var path = require('path');
4var checker = require('ember-cli-version-checker');
5var utils = require('./utils');
6var hashForDep = require('hash-for-dep');
7
8module.exports = {
9 name: 'ember-cli-htmlbars',
10
11 init: function() {
12 if (this._super.init) { this._super.init.apply(this, arguments); }
13 checker.assertAbove(this, '0.1.2');
14 },
15
16 parentRegistry: null,
17
18 shouldSetupRegistryInIncluded: function() {
19 return !checker.isAbove(this, '0.2.0');
20 },
21
22 purgeModule: function(templateCompilerPath) {
23 // ensure we get a fresh templateCompilerModuleInstance per ember-addon
24 // instance NOTE: this is a quick hack, and will only work as long as
25 // templateCompilerPath is a single file bundle
26 //
27 // (╯°□°)╯︵ ɹǝqɯǝ
28 //
29 // we will also fix this in ember for future releases
30
31 // Module will be cached in .parent.children as well. So deleting from require.cache alone is not sufficient.
32 var mod = require.cache[templateCompilerPath];
33 if (mod && mod.parent) {
34 var index = mod.parent.children.indexOf(mod);
35 if (index >= 0) {
36 mod.parent.children.splice(index, 1);
37 } else {
38 throw new TypeError("ember-cli-htmlbars attempted to purge '" + templateCompilerPath + "' but something went wrong.");
39 }
40 }
41
42 delete require.cache[templateCompilerPath];
43 },
44
45 setupPreprocessorRegistry: function(type, registry) {
46 // ensure that broccoli-ember-hbs-template-compiler is not processing hbs files
47 registry.remove('template', 'broccoli-ember-hbs-template-compiler');
48
49 registry.add('template', {
50 name: 'ember-cli-htmlbars',
51 ext: 'hbs',
52 _addon: this,
53 toTree: function(tree) {
54 var htmlbarsOptions = this._addon.htmlbarsOptions();
55 return require('./index')(tree, htmlbarsOptions);
56 },
57
58 precompile: function(string) {
59 var htmlbarsOptions = this._addon.htmlbarsOptions();
60 var templateCompiler = htmlbarsOptions.templateCompiler;
61 return utils.template(templateCompiler, string);
62 }
63 });
64
65 if (type === 'parent') {
66 this.parentRegistry = registry;
67 }
68 },
69
70 included: function (app) {
71 this._super.included.apply(this, arguments);
72
73 if (this.shouldSetupRegistryInIncluded()) {
74 this.setupPreprocessorRegistry('parent', app.registry);
75 }
76 },
77
78 projectConfig: function () {
79 return this.project.config(process.env.EMBER_ENV);
80 },
81
82 templateCompilerPath: function() {
83 var config = this.projectConfig();
84 var templateCompilerPath = config['ember-cli-htmlbars'] && config['ember-cli-htmlbars'].templateCompilerPath;
85
86 var ember = this.project.findAddonByName('ember-source');
87 if (ember) {
88 return ember.absolutePaths.templateCompiler;
89 } else if (!templateCompilerPath) {
90 templateCompilerPath = this.project.bowerDirectory + '/ember/ember-template-compiler';
91 }
92
93 var absolutePath = path.resolve(this.project.root, templateCompilerPath);
94
95 if (path.extname(absolutePath) === '') {
96 absolutePath += '.js';
97 }
98
99 return absolutePath;
100 },
101
102 htmlbarsOptions: function() {
103 var projectConfig = this.projectConfig() || {};
104 var EmberENV = projectConfig.EmberENV || {};
105 var templateCompilerPath = this.templateCompilerPath();
106
107 this.purgeModule(templateCompilerPath);
108
109 var clonedEmberENV = JSON.parse(JSON.stringify(EmberENV));
110 global.EmberENV = clonedEmberENV; // Needed for eval time feature flag checks
111 var pluginInfo = this.astPlugins();
112
113 var htmlbarsOptions = {
114 isHTMLBars: true,
115 EmberENV: EmberENV,
116 templateCompiler: require(templateCompilerPath),
117 templateCompilerPath: templateCompilerPath,
118
119 plugins: {
120 ast: pluginInfo.plugins
121 },
122
123 pluginCacheKey: pluginInfo.cacheKeys
124 };
125
126 this.purgeModule(templateCompilerPath);
127
128 delete global.Ember;
129 delete global.EmberENV;
130
131 return htmlbarsOptions;
132 },
133
134 astPlugins: function() {
135 var pluginWrappers = this.parentRegistry.load('htmlbars-ast-plugin');
136 var plugins = [];
137 var cacheKeys = [];
138
139 for (var i = 0; i < pluginWrappers.length; i++) {
140 var wrapper = pluginWrappers[i];
141
142 plugins.push(wrapper.plugin);
143
144 var providesBaseDir = typeof wrapper.baseDir === 'function';
145 var augmentsCacheKey = typeof wrapper.cacheKey === 'function';
146
147 if (providesBaseDir || augmentsCacheKey) {
148 if (providesBaseDir) {
149 var pluginHashForDep = hashForDep(wrapper.baseDir());
150 cacheKeys.push(pluginHashForDep);
151 }
152 if (augmentsCacheKey) {
153 cacheKeys.push(wrapper.cacheKey());
154 }
155 } else {
156 // support for ember-cli < 2.2.0
157 var log = this.ui.writeDeprecateLine || this.ui.writeLine;
158
159 log.call(this.ui, 'ember-cli-htmlbars is opting out of caching due to an AST plugin that does not provide a caching strategy: `' + wrapper.name + '`.');
160 cacheKeys.push((new Date()).getTime() + '|' + Math.random());
161 }
162 }
163
164 return {
165 plugins: plugins,
166 cacheKeys: cacheKeys
167 };
168 }
169};