UNPKG

8.86 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
6
7const Asset = require('../Asset');
8
9const localRequire = require('../utils/localRequire');
10
11const md5 = require('../utils/md5');
12
13const _require = require('terser'),
14 minify = _require.minify;
15
16const t = require('@babel/types');
17
18class VueAsset extends Asset {
19 constructor(name, options) {
20 super(name, options);
21 this.type = 'js';
22 }
23
24 parse(code) {
25 var _this = this;
26
27 return (0, _asyncToGenerator2.default)(function* () {
28 // Is being used in component-compiler-utils, errors if not installed...
29 _this.vueTemplateCompiler = yield localRequire('vue-template-compiler', _this.name);
30 _this.vue = yield localRequire('@vue/component-compiler-utils', _this.name);
31 return _this.vue.parse({
32 source: code,
33 needMap: _this.options.sourceMaps,
34 filename: _this.relativeName,
35 // Used for sourcemaps
36 sourceRoot: '',
37 // Used for sourcemaps. Override so it doesn't use cwd
38 compiler: _this.vueTemplateCompiler
39 });
40 })();
41 }
42
43 generate() {
44 var _this2 = this;
45
46 return (0, _asyncToGenerator2.default)(function* () {
47 let descriptor = _this2.ast;
48 let parts = [];
49
50 if (descriptor.script) {
51 parts.push({
52 type: descriptor.script.lang || 'js',
53 value: descriptor.script.content,
54 map: descriptor.script.map
55 });
56 }
57
58 if (descriptor.template) {
59 parts.push({
60 type: descriptor.template.lang || 'html',
61 value: descriptor.template.content.trim()
62 });
63 }
64
65 if (descriptor.styles) {
66 var _iteratorNormalCompletion = true;
67 var _didIteratorError = false;
68 var _iteratorError = undefined;
69
70 try {
71 for (var _iterator = descriptor.styles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
72 let style = _step.value;
73 parts.push({
74 type: style.lang || 'css',
75 value: style.content.trim(),
76 modules: !!style.module
77 });
78 }
79 } catch (err) {
80 _didIteratorError = true;
81 _iteratorError = err;
82 } finally {
83 try {
84 if (!_iteratorNormalCompletion && _iterator.return != null) {
85 _iterator.return();
86 }
87 } finally {
88 if (_didIteratorError) {
89 throw _iteratorError;
90 }
91 }
92 }
93 }
94
95 return parts;
96 })();
97 }
98
99 postProcess(generated) {
100 var _this3 = this;
101
102 return (0, _asyncToGenerator2.default)(function* () {
103 let result = [];
104
105 let hasScoped = _this3.ast.styles.some(s => s.scoped);
106
107 let id = md5(_this3.name).slice(-6);
108 let scopeId = hasScoped ? `data-v-${id}` : null;
109 let optsVar = '$' + id; // Generate JS output.
110
111 let js = _this3.ast.script ? generated[0].value : '';
112 let supplemental = ''; // TODO: make it possible to process this code with the normal scope hoister
113
114 if (_this3.options.scopeHoist) {
115 optsVar = `$${t.toIdentifier(_this3.id)}$export$default`;
116
117 if (!js.includes(optsVar)) {
118 optsVar = `$${t.toIdentifier(_this3.id)}$exports`;
119
120 if (!js.includes(optsVar)) {
121 supplemental += `
122 var ${optsVar} = {};
123 `;
124 _this3.cacheData.isCommonJS = true;
125 }
126 }
127 } else {
128 supplemental += `
129 var ${optsVar} = exports.default || module.exports;
130 `;
131 }
132
133 supplemental += `
134 if (typeof ${optsVar} === 'function') {
135 ${optsVar} = ${optsVar}.options;
136 }
137 `;
138 supplemental += _this3.compileTemplate(generated, scopeId, optsVar);
139 supplemental += _this3.compileCSSModules(generated, optsVar);
140 supplemental += _this3.compileHMR(generated, optsVar);
141
142 if (_this3.options.minify && !_this3.options.scopeHoist) {
143 let _minify = minify(supplemental, {
144 toplevel: true
145 }),
146 code = _minify.code,
147 error = _minify.error;
148
149 if (error) {
150 throw error;
151 }
152
153 supplemental = code;
154
155 if (supplemental) {
156 supplemental = `\n(function(){${supplemental}})();`;
157 }
158 }
159
160 js += supplemental;
161
162 if (js) {
163 result.push({
164 type: 'js',
165 value: js,
166 map: _this3.options.sourceMaps && _this3.ast.script && generated[0].map
167 });
168 }
169
170 let css = _this3.compileStyle(generated, scopeId);
171
172 if (css) {
173 result.push({
174 type: 'css',
175 value: css
176 });
177 }
178
179 return result;
180 })();
181 }
182
183 compileTemplate(generated, scopeId, optsVar) {
184 let html = generated.find(r => r.type === 'html');
185
186 if (html) {
187 let isFunctional = this.ast.template.attrs.functional;
188 let template = this.vue.compileTemplate({
189 source: html.value,
190 filename: this.relativeName,
191 compiler: this.vueTemplateCompiler,
192 isProduction: this.options.production,
193 isFunctional,
194 compilerOptions: {
195 scopeId
196 }
197 });
198
199 if (Array.isArray(template.errors) && template.errors.length >= 1) {
200 throw new Error(template.errors[0]);
201 }
202
203 return `
204 /* template */
205 Object.assign(${optsVar}, (function () {
206 ${template.code}
207 return {
208 render: render,
209 staticRenderFns: staticRenderFns,
210 _compiled: true,
211 _scopeId: ${JSON.stringify(scopeId)},
212 functional: ${JSON.stringify(isFunctional)}
213 };
214 })());
215 `;
216 }
217
218 return '';
219 }
220
221 compileCSSModules(generated, optsVar) {
222 let cssRenditions = generated.filter(r => r.type === 'css');
223 let cssModulesCode = '';
224 this.ast.styles.forEach((style, index) => {
225 if (style.module) {
226 let cssModules = JSON.stringify(cssRenditions[index].cssModules);
227 let name = style.module === true ? '$style' : style.module;
228 cssModulesCode += `\nthis[${JSON.stringify(name)}] = ${cssModules};`;
229 }
230 });
231
232 if (cssModulesCode) {
233 cssModulesCode = `function hook(){${cssModulesCode}\n}`;
234 let isFunctional = this.ast.template && this.ast.template.attrs.functional;
235
236 if (isFunctional) {
237 return `
238 /* css modules */
239 (function () {
240 ${cssModulesCode}
241 ${optsVar}._injectStyles = hook;
242 var originalRender = ${optsVar}.render;
243 ${optsVar}.render = function (h, context) {
244 hook.call(context);
245 return originalRender(h, context);
246 };
247 })();
248 `;
249 } else {
250 return `
251 /* css modules */
252 (function () {
253 ${cssModulesCode}
254 ${optsVar}.beforeCreate = ${optsVar}.beforeCreate ? ${optsVar}.beforeCreate.concat(hook) : [hook];
255 })();
256 `;
257 }
258 }
259
260 return '';
261 }
262
263 compileStyle(generated, scopeId) {
264 return generated.filter(r => r.type === 'css').reduce((p, r, i) => {
265 let css = r.value;
266 let scoped = this.ast.styles[i].scoped; // Process scoped styles if needed.
267
268 if (scoped) {
269 let _this$vue$compileStyl = this.vue.compileStyle({
270 source: css,
271 filename: this.relativeName,
272 id: scopeId,
273 scoped
274 }),
275 code = _this$vue$compileStyl.code,
276 errors = _this$vue$compileStyl.errors;
277
278 if (errors.length) {
279 throw errors[0];
280 }
281
282 css = code;
283 }
284
285 return p + css;
286 }, '');
287 }
288
289 compileHMR(generated, optsVar) {
290 if (!this.options.hmr) {
291 return '';
292 }
293
294 this.addDependency('vue-hot-reload-api');
295 this.addDependency('vue');
296 let cssHMR = '';
297
298 if (this.ast.styles.length) {
299 cssHMR = `
300 var reloadCSS = require('_css_loader');
301 module.hot.dispose(reloadCSS);
302 module.hot.accept(reloadCSS);
303 `;
304 }
305
306 let isFunctional = this.ast.template && this.ast.template.attrs.functional;
307 return `
308 /* hot reload */
309 (function () {
310 if (module.hot) {
311 var api = require('vue-hot-reload-api');
312 api.install(require('vue'));
313 if (api.compatible) {
314 module.hot.accept();
315 if (!module.hot.data) {
316 api.createRecord('${optsVar}', ${optsVar});
317 } else {
318 api.${isFunctional ? 'rerender' : 'reload'}('${optsVar}', ${optsVar});
319 }
320 }
321
322 ${cssHMR}
323 }
324 })();`;
325 }
326
327}
328
329module.exports = VueAsset;
\No newline at end of file