UNPKG

5 kBJavaScriptView Raw
1const {
2 join,
3 dirname,
4} = require('path');
5const {
6 readFileSync,
7} = require('fs');
8const {
9 spawnSync,
10} = require('child_process');
11const compiler = require('vue-template-compiler');
12const transpile = require('vue-template-es2015-compiler');
13const postcss = require('postcss');
14const postcssModules = require('postcss-modules-sync').default;
15
16const COMPONENT_OPTIONS = '((module.exports.default || module.exports).options || module.exports.default || module.exports)';
17
18const defaultConfig = {
19 transpileTemplates: true,
20 sourceMaps: true,
21};
22
23let globalConfig = Object.assign({}, defaultConfig);
24
25let sourceMapSupport = false;
26
27function retrieveContent(
28 filename,
29 config
30) {
31 if (config.attrs.src) {
32 const fullPath = join(dirname(filename), config.attrs.src);
33 return readFileSync(fullPath, 'utf8');
34 } else if (config.content) {
35 return config.content;
36 }
37
38 return '';
39}
40
41function retrieveAndTranspileContent(
42 filename,
43 config,
44 hook,
45 noTranspileLangs,
46 transpileSpecial
47) {
48 const content = retrieveContent(filename, config);
49 const lang = (config.attrs.lang || '').toLowerCase();
50
51 if (lang && noTranspileLangs.includes(lang) === false) {
52 if (transpileSpecial == null) {
53 return hook(lang, content);
54 } else {
55 return transpileSpecial(content, lang);
56 }
57 }
58
59 return content;
60}
61
62function getScriptPart(
63 filename,
64 hook,
65 script
66) {
67 if (!script) {
68 return 'module.exports = { functional: true }';
69 }
70 return retrieveAndTranspileContent(
71 filename,
72 script,
73 hook,
74 [ 'js', 'javascript' ]
75 );
76}
77
78function transpileTemplateSpecial(
79 content,
80 lang
81) {
82 const result = spawnSync(
83 process.execPath,
84 [
85 join(__dirname, './renderTemplate.js'),
86 lang,
87 content,
88 ],
89 {
90 encoding: 'utf-8',
91 }
92 );
93
94 if (result.stderr) {
95 throw new Error(result.stderr);
96 }
97
98 return result.stdout;
99}
100
101function getCompiledTemplate(
102 filename,
103 hook,
104 template
105) {
106 if (!template) {
107 return '';
108 }
109
110 const content = retrieveAndTranspileContent(
111 filename,
112 template,
113 hook,
114 [ 'html' ],
115 globalConfig.transpileTemplates && transpileTemplateSpecial
116 );
117
118 const compiled = compiler.compile(content, { preserveWhitespace: false });
119 const renderFn = `function(){ ${compiled.render} }`;
120 const staticRenderFns = (compiled.staticRenderFns || [])
121 .map((fn) => `function(){ ${fn} }`)
122 .join(',');
123
124 return [
125 ';',
126 transpile(`${COMPONENT_OPTIONS}.render=${renderFn};`),
127 transpile(`${COMPONENT_OPTIONS}.staticRenderFns = [ ${staticRenderFns} ];`),
128 `${COMPONENT_OPTIONS}.render._withStripped = true;`,
129 ].join('\n');
130}
131
132function getCssModuleComputedProps(
133 filename,
134 hook,
135 styles
136) {
137 if (!styles) {
138 return '';
139 }
140
141 const computedProps = styles
142 .filter((style) => style.module !== undefined && style.module !== false)
143 .map((style) => {
144 const moduleName = (typeof style.module) === 'string' ? style.module : '$style';
145 const content = retrieveAndTranspileContent(
146 filename,
147 style,
148 hook,
149 [ 'css' ]
150 );
151
152 let cssClasses;
153 postcss(postcssModules(
154 {
155 generateScopedName: moduleName + '-[local]',
156 getJSON: json => { cssClasses = json; }
157 })).process(content).css;
158 const cssClassesStr = JSON.stringify(cssClasses);
159
160 return `${COMPONENT_OPTIONS}.computed.${moduleName} = function(){ return ${cssClassesStr}; };`;
161 });
162
163 if (!computedProps.length) {
164 return '';
165 }
166
167 return `${COMPONENT_OPTIONS}.computed = ${COMPONENT_OPTIONS}.computed || {}; ${computedProps.join(' ')}`;
168}
169
170function processCustomBlocks (
171 filename,
172 hook,
173 customBlocks
174) {
175 if (!customBlocks)
176 return '';
177 return customBlocks.map(customBlock => {
178 try {
179 return hook('vue-block-' + customBlock.type, customBlock.content);
180 } catch (err) {
181 return '';
182 }
183 }).join('\n');
184}
185
186module.exports = ({ content, filename, hook }) => {
187 const {
188 template,
189 script,
190 styles,
191 customBlocks,
192 } = compiler.parseComponent(content, { pad: 'line' });
193
194 if (globalConfig.sourceMaps && sourceMapSupport === false) {
195 require('source-map-support').install({
196 hookRequired: true,
197 });
198 sourceMapSupport = true;
199 }
200
201 const scriptPart = getScriptPart(
202 filename,
203 hook,
204 script
205 );
206
207 const compiledTemplate = getCompiledTemplate(
208 filename,
209 hook,
210 template
211 );
212
213 const cssModulesComputedProps = getCssModuleComputedProps(
214 filename,
215 hook,
216 styles
217 );
218
219 const processedCustomBlocks = processCustomBlocks(
220 filename,
221 hook,
222 customBlocks
223 );
224
225 const result = [
226 scriptPart,
227 compiledTemplate,
228 cssModulesComputedProps,
229 processedCustomBlocks,
230 ].join('\n');
231
232 return { content: result };
233};
234
235module.exports.configure = (config) => {
236 globalConfig = Object.assign({}, defaultConfig, globalConfig, config);
237};
238
239module.exports.COMPONENT_OPTIONS = COMPONENT_OPTIONS;