1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const source_map_1 = require("source-map");
|
4 | const source_map_2 = require("./source-map");
|
5 | const path = require("path");
|
6 | function assemble(compiler, filename, result, options = {}) {
|
7 | return assembleFromSource(compiler, options, {
|
8 | filename,
|
9 | scopeId: result.scopeId,
|
10 | script: result.script && {
|
11 | source: result.script.code,
|
12 | map: result.script.map
|
13 | },
|
14 | template: result.template && Object.assign({}, result.template, { source: result.template.code, functional: result.template.functional }),
|
15 | styles: result.styles.map(style => {
|
16 | if (style.errors.length) {
|
17 | console.error(style.errors);
|
18 | }
|
19 | return Object.assign({}, style, { source: style.code, media: style.media, scoped: style.scoped, moduleName: style.moduleName, module: style.module });
|
20 | })
|
21 | });
|
22 | }
|
23 | exports.assemble = assemble;
|
24 | function assembleFromSource(compiler, options, { filename, script, template, styles, scopeId }) {
|
25 | script = script || { source: 'export default {}' };
|
26 | template = template || { source: '' };
|
27 | let map = undefined;
|
28 | const mapGenerator = new source_map_1.SourceMapGenerator({ file: filename.replace(/\\/g, '/') });
|
29 | const hasScopedStyle = styles.some(style => style.scoped === true);
|
30 | const hasStyle = styles.some(style => style.source || style.module);
|
31 | const e = (any) => JSON.stringify(any);
|
32 | const createImport = (name, value) => value.startsWith('~')
|
33 | ? `import ${name} from '${value.substr(1)}'`
|
34 | : `const ${name} = ${value}`;
|
35 | const o = e;
|
36 | const IDENTIFIER = /^[a-z0-9]+$/i;
|
37 |
|
38 | const inlineCreateInjector = `function __vue_create_injector__() {
|
39 | const styles = __vue_create_injector__.styles || (__vue_create_injector__.styles = {})
|
40 | const isOldIE =
|
41 | typeof navigator !== 'undefined' &&
|
42 | /msie [6-9]\\\\b/.test(navigator.userAgent.toLowerCase())
|
43 |
|
44 | return function addStyle(id, css) {
|
45 | if (document.querySelector('style[data-vue-ssr-id~="' + id + '"]')) return // SSR styles are present.
|
46 |
|
47 | const group = isOldIE ? css.media || 'default' : id
|
48 | const style = styles[group] || (styles[group] = { ids: [], parts: [], element: undefined })
|
49 |
|
50 | if (!style.ids.includes(id)) {
|
51 | let code = css.source
|
52 | let index = style.ids.length
|
53 |
|
54 | style.ids.push(id)
|
55 |
|
56 | if (${e(compiler.template.isProduction)} && css.map) {
|
57 | // https://developer.chrome.com/devtools/docs/javascript-debugging
|
58 | // this makes source maps inside style tags work properly in Chrome
|
59 | code += '\\n/*# sourceURL=' + css.map.sources[0] + ' */'
|
60 | // http://stackoverflow.com/a/26603875
|
61 | code +=
|
62 | '\\n/*# sourceMappingURL=data:application/json;base64,' +
|
63 | btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
|
64 | ' */'
|
65 | }
|
66 |
|
67 | if (isOldIE) {
|
68 | style.element = style.element || document.querySelector('style[data-group=' + group + ']')
|
69 | }
|
70 |
|
71 | if (!style.element) {
|
72 | const head = document.head || document.getElementsByTagName('head')[0]
|
73 | const el = style.element = document.createElement('style')
|
74 | el.type = 'text/css'
|
75 |
|
76 | if (css.media) el.setAttribute('media', css.media)
|
77 | if (isOldIE) {
|
78 | el.setAttribute('data-group', group)
|
79 | el.setAttribute('data-next-index', '0')
|
80 | }
|
81 |
|
82 | head.appendChild(el)
|
83 | }
|
84 |
|
85 | if (isOldIE) {
|
86 | index = parseInt(style.element.getAttribute('data-next-index'))
|
87 | style.element.setAttribute('data-next-index', index + 1)
|
88 | }
|
89 |
|
90 | if (style.element.styleSheet) {
|
91 | style.parts.push(code)
|
92 | style.element.styleSheet.cssText = style.parts
|
93 | .filter(Boolean)
|
94 | .join('\\n')
|
95 | } else {
|
96 | const textNode = document.createTextNode(code)
|
97 | const nodes = style.element.childNodes
|
98 | if (nodes[index]) style.element.removeChild(nodes[index])
|
99 | if (nodes.length) style.element.insertBefore(textNode, nodes[index])
|
100 | else style.element.appendChild(textNode)
|
101 | }
|
102 | }
|
103 | }
|
104 | }`;
|
105 | const createInjector = options.styleInjector
|
106 | ? createImport('__vue_create_injector__', options.styleInjector)
|
107 | : inlineCreateInjector;
|
108 |
|
109 | const inlineCreateInjectorSSR = `function __vue_create_injector_ssr__(context) {
|
110 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
|
111 | context = __VUE_SSR_CONTEXT__
|
112 | }
|
113 |
|
114 | if (!context) return function () {}
|
115 |
|
116 | if (!context.hasOwnProperty('styles')) {
|
117 | Object.defineProperty(context, 'styles', {
|
118 | enumerable: true,
|
119 | get: () => context._styles
|
120 | })
|
121 | context._renderStyles = renderStyles
|
122 | }
|
123 |
|
124 | function renderStyles(styles) {
|
125 | let css = ''
|
126 | for (const {ids, media, parts} of styles) {
|
127 | css +=
|
128 | '<style data-vue-ssr-id="' + ids.join(' ') + '"' + (media ? ' media="' + media + '"' : '') + '>'
|
129 | + parts.join('\\n') +
|
130 | '</style>'
|
131 | }
|
132 |
|
133 | return css
|
134 | }
|
135 |
|
136 | return function addStyle(id, css) {
|
137 | const group = ${e(compiler.template.isProduction)} ? css.media || 'default' : id
|
138 | const style = context._styles[group] || (context._styles[group] = { ids: [], parts: [] })
|
139 |
|
140 | if (!style.ids.includes(id)) {
|
141 | style.media = css.media
|
142 | style.ids.push(id)
|
143 | let code = css.source
|
144 | if (${e(!compiler.template.isProduction)} && css.map) {
|
145 | // https://developer.chrome.com/devtools/docs/javascript-debugging
|
146 | // this makes source maps inside style tags work properly in Chrome
|
147 | code += '\\n/*# sourceURL=' + css.map.sources[0] + ' */'
|
148 | // http://stackoverflow.com/a/26603875
|
149 | code +=
|
150 | '\\n/*# sourceMappingURL=data:application/json;base64,' +
|
151 | btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
|
152 | ' */'
|
153 | }
|
154 | style.parts.push(code)
|
155 | }
|
156 | }
|
157 | }`;
|
158 | const createInjectorSSR = options.styleInjectorSSR
|
159 | ? createImport('__vue_create_injector_ssr__', options.styleInjectorSSR)
|
160 | : inlineCreateInjectorSSR;
|
161 | const inlineCreateInjectorShadow = `function __vue_create_injector_shadow__(__, shadowRoot) {
|
162 | function createStyleElement(shadowRoot) {
|
163 | var styleElement = document.createElement('style')
|
164 | styleElement.type = 'text/css'
|
165 | shadowRoot.appendChild(styleElement)
|
166 |
|
167 | return styleElement
|
168 | }
|
169 |
|
170 | return function addStyle(id, css) {
|
171 | const styleElement = createStyleElement(shadowRoot)
|
172 | if (css.media) styleElement.setAttribute('media', css.media)
|
173 |
|
174 | let code = css.source
|
175 |
|
176 | if (${e(compiler.template.isProduction)} && css.map) {
|
177 | // https://developer.chrome.com/devtools/docs/javascript-debugging
|
178 | // this makes source maps inside style tags work properly in Chrome
|
179 | code += '\\n/*# sourceURL=' + css.map.sources[0] + ' */'
|
180 | // http://stackoverflow.com/a/26603875
|
181 | code +=
|
182 | '\\n/*# sourceMappingURL=data:application/json;base64,' +
|
183 | btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
|
184 | ' */'
|
185 | }
|
186 |
|
187 | if ('styleSheet' in styleElement) {
|
188 | styleElement.styleSheet.cssText = code
|
189 | } else {
|
190 | while (styleElement.firstChild) {
|
191 | styleElement.removeChild(styleElement.firstChild)
|
192 | }
|
193 | styleElement.appendChild(document.createTextNode(code))
|
194 | }
|
195 | }
|
196 | }`;
|
197 | const createInjectorShadow = options.styleInjectorShadow
|
198 | ? createImport('__vue_create_injector_shadow__', options.styleInjectorShadow)
|
199 | : inlineCreateInjectorShadow;
|
200 |
|
201 | const inlineNormalizeComponent = `function __vue_normalize__(
|
202 | template, style, script,
|
203 | scope, functional, moduleIdentifier, shadowMode,
|
204 | createInjector, createInjectorSSR, createInjectorShadow
|
205 | ) {
|
206 | const component = (typeof script === 'function' ? script.options : script) || {}
|
207 |
|
208 | // For security concerns, we use only base name in production mode.
|
209 | component.__file = ${compiler.template.isProduction ? e(path.basename(filename)) : e(filename)}
|
210 |
|
211 | if (!component.render) {
|
212 | component.render = template.render
|
213 | component.staticRenderFns = template.staticRenderFns
|
214 | component._compiled = true
|
215 |
|
216 | if (functional) component.functional = true
|
217 | }
|
218 |
|
219 | component._scopeId = scope
|
220 |
|
221 | if (${e(hasStyle)}) {
|
222 | let hook
|
223 | if (${e(compiler.template.optimizeSSR)}) {
|
224 | // In SSR.
|
225 | hook = function(context) {
|
226 | // 2.3 injection
|
227 | context =
|
228 | context || // cached call
|
229 | (this.$vnode && this.$vnode.ssrContext) || // stateful
|
230 | (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
|
231 | // 2.2 with runInNewContext: true
|
232 | if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
|
233 | context = __VUE_SSR_CONTEXT__
|
234 | }
|
235 | // inject component styles
|
236 | if (style) {
|
237 | style.call(this, createInjectorSSR(context))
|
238 | }
|
239 | // register component module identifier for async chunk inference
|
240 | if (context && context._registeredComponents) {
|
241 | context._registeredComponents.add(moduleIdentifier)
|
242 | }
|
243 | }
|
244 | // used by ssr in case component is cached and beforeCreate
|
245 | // never gets called
|
246 | component._ssrRegister = hook
|
247 | }
|
248 | else if (style) {
|
249 | hook = shadowMode
|
250 | ? function(context) {
|
251 | style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot))
|
252 | }
|
253 | : function(context) {
|
254 | style.call(this, createInjector(context))
|
255 | }
|
256 | }
|
257 |
|
258 | if (hook !== undefined) {
|
259 | if (component.functional) {
|
260 | // register for functional component in vue file
|
261 | const originalRender = component.render
|
262 | component.render = function renderWithStyleInjection(h, context) {
|
263 | hook.call(context)
|
264 | return originalRender(h, context)
|
265 | }
|
266 | } else {
|
267 | // inject component registration as beforeCreate hook
|
268 | const existing = component.beforeCreate
|
269 | component.beforeCreate = existing ? [].concat(existing, hook) : [hook]
|
270 | }
|
271 | }
|
272 | }
|
273 |
|
274 | return component
|
275 | }`;
|
276 | const normalizeComponent = options.normalizer
|
277 | ? createImport('__vue_normalize__', options.normalizer)
|
278 | : inlineNormalizeComponent;
|
279 | const DEFAULT_EXPORT = 'const __vue_script__ =';
|
280 |
|
281 | let code = `/* script */\n${script.source.replace(/export\s+default/, DEFAULT_EXPORT)}` +
|
282 | `\n/* template */\n${template.source
|
283 | .replace('var render =', 'var __vue_render__ =')
|
284 | .replace('var staticRenderFns =', 'var __vue_staticRenderFns__ =')
|
285 | .replace('render._withStripped =', '__vue_render__._withStripped =')}
|
286 | /* style */
|
287 | const __vue_inject_styles__ = ${hasStyle ? `function (inject) {
|
288 | if (!inject) return
|
289 | ${styles.map((style, index) => {
|
290 | const source = IDENTIFIER.test(style.source)
|
291 | ? style.source
|
292 | : e(style.source);
|
293 | const map = !compiler.template.isProduction
|
294 | ? typeof style.map === 'string' && IDENTIFIER.test(style.map)
|
295 | ? style.map
|
296 | : o(style.map)
|
297 | : undefined;
|
298 | const tokens = typeof style.module === 'string' && IDENTIFIER.test(style.module)
|
299 | ? style.module
|
300 | : o(style.module);
|
301 | return ((source
|
302 | ? `inject("${scopeId +
|
303 | '_' +
|
304 | index}", { source: ${source}, map: ${map}, media: ${e(style.media)} })\n`
|
305 | : '') +
|
306 | (style.moduleName
|
307 | ? `Object.defineProperty(this, "${style.moduleName}", { value: ${tokens} })` + '\n'
|
308 | : ''));
|
309 | })}
|
310 | }` : 'undefined'}
|
311 | /* scoped */
|
312 | const __vue_scope_id__ = ${hasScopedStyle ? e(scopeId) : 'undefined'}
|
313 | /* module identifier */
|
314 | const __vue_module_identifier__ = ${compiler.template.optimizeSSR ? e(scopeId) : 'undefined'}
|
315 | /* functional template */
|
316 | const __vue_is_functional_template__ = ${e(template.functional)}
|
317 | /* component normalizer */
|
318 | ${normalizeComponent}
|
319 | /* style inject */
|
320 | ${hasStyle && !compiler.template.optimizeSSR && !options.isWebComponent ? createInjector : ''}
|
321 | /* style inject SSR */
|
322 | ${hasStyle && compiler.template.optimizeSSR ? createInjectorSSR : ''}
|
323 | /* style inject shadow dom */
|
324 | ${hasStyle && options.isWebComponent ? createInjectorShadow : ''}
|
325 |
|
326 | `;
|
327 |
|
328 | {
|
329 | const input = script.source.split('\n');
|
330 | input.forEach((sourceLine, index) => {
|
331 | if (!sourceLine)
|
332 | return;
|
333 | const matches = /export\s+default/.exec(sourceLine);
|
334 | if (matches) {
|
335 | const pos = sourceLine.indexOf(matches[0]);
|
336 | if (pos > 0) {
|
337 | mapGenerator.addMapping({
|
338 | source: filename,
|
339 | original: { line: index + 1, column: 0 },
|
340 | generated: { line: index + 2, column: 0 }
|
341 | });
|
342 | }
|
343 | mapGenerator.addMapping({
|
344 | source: filename,
|
345 | original: { line: index + 1, column: pos },
|
346 | generated: { line: index + 2, column: pos }
|
347 | });
|
348 | if (sourceLine.substr(pos + matches[0].length)) {
|
349 | mapGenerator.addMapping({
|
350 | source: filename,
|
351 | original: { line: index + 1, column: pos + matches[0].length },
|
352 | generated: { line: index + 2, column: pos + DEFAULT_EXPORT.length }
|
353 | });
|
354 | }
|
355 | }
|
356 | else {
|
357 | mapGenerator.addMapping({
|
358 | source: filename,
|
359 | original: { line: index + 1, column: 0 },
|
360 | generated: { line: index + 2, column: 0 }
|
361 | });
|
362 | }
|
363 | });
|
364 | }
|
365 | code += `
|
366 | const __vue_component__ = /*#__PURE__*/__vue_normalize__(
|
367 | ${code.indexOf('__vue_render__') > -1
|
368 | ? '{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }'
|
369 | : '{}'},
|
370 | __vue_inject_styles__,
|
371 | ${code.indexOf('__vue_script__') > -1 ? '__vue_script__' : '{}'},
|
372 | __vue_scope_id__,
|
373 | __vue_is_functional_template__,
|
374 | __vue_module_identifier__,
|
375 | ${options.isWebComponent ? 'true' : 'false'},
|
376 | ${code.indexOf('__vue_create_injector__') > -1
|
377 | ? '__vue_create_injector__'
|
378 | : 'undefined'},
|
379 | ${code.indexOf('__vue_create_injector_ssr__') > -1
|
380 | ? '__vue_create_injector_ssr__'
|
381 | : 'undefined'},
|
382 | ${code.indexOf('__vue_create_injector_shadow__') > -1
|
383 | ? '__vue_create_injector_shadow__'
|
384 | : 'undefined'}
|
385 | )\n
|
386 | export default __vue_component__`;
|
387 | if (script.map) {
|
388 | map = source_map_2.merge(script.map, JSON.parse(mapGenerator.toString()));
|
389 | }
|
390 | else {
|
391 | map = JSON.parse(mapGenerator.toString());
|
392 | }
|
393 | return { code, map };
|
394 | }
|
395 | exports.assembleFromSource = assembleFromSource;
|