1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | try {
|
7 | require.resolve('@vue/compiler-sfc');
|
8 | }
|
9 | catch (e) {
|
10 | throw new Error('rollup-plugin-vue requires @vue/compiler-sfc to be present in the dependency ' +
|
11 | 'tree.');
|
12 | }
|
13 | const compiler_sfc_1 = require("@vue/compiler-sfc");
|
14 | const fs_1 = __importDefault(require("fs"));
|
15 | const debug_1 = __importDefault(require("debug"));
|
16 | const hash_sum_1 = __importDefault(require("hash-sum"));
|
17 | const path_1 = require("path");
|
18 | const querystring_1 = __importDefault(require("querystring"));
|
19 | const rollup_pluginutils_1 = require("rollup-pluginutils");
|
20 | const debug = debug_1.default('rollup-plugin-vue');
|
21 | const defaultOptions = {
|
22 | include: /\.vue$/,
|
23 | exclude: [],
|
24 | target: 'browser',
|
25 | exposeFilename: false,
|
26 | customBlocks: [],
|
27 | };
|
28 | function PluginVue(userOptions = {}) {
|
29 | const options = {
|
30 | ...defaultOptions,
|
31 | ...userOptions,
|
32 | };
|
33 | const isServer = options.target === 'node';
|
34 | const isProduction = process.env.NODE_ENV === 'production' || process.env.BUILD === 'production';
|
35 | const rootContext = process.cwd();
|
36 | const filter = rollup_pluginutils_1.createFilter(options.include, options.exclude);
|
37 | const filterCustomBlock = createCustomBlockFilter(options.customBlocks);
|
38 | return {
|
39 | name: 'vue',
|
40 | async resolveId(id, importer) {
|
41 | const query = parseVuePartRequest(id);
|
42 | if (query.vue) {
|
43 | if (query.src) {
|
44 | const resolved = await this.resolve(query.filename, importer, {
|
45 | skipSelf: true,
|
46 | });
|
47 | if (resolved) {
|
48 | cache.set(resolved.id, getDescriptor(importer));
|
49 | const [, originalQuery] = id.split('?', 2);
|
50 | resolved.id += `?${originalQuery}`;
|
51 | return resolved;
|
52 | }
|
53 | }
|
54 | else if (!filter(query.filename)) {
|
55 | return undefined;
|
56 | }
|
57 | debug(`resolveId(${id})`);
|
58 | return id;
|
59 | }
|
60 | return undefined;
|
61 | },
|
62 | load(id) {
|
63 | const query = parseVuePartRequest(id);
|
64 | if (query.vue) {
|
65 | if (query.src) {
|
66 | return fs_1.default.readFileSync(query.filename, 'utf-8');
|
67 | }
|
68 | const descriptor = getDescriptor(query.filename);
|
69 | if (descriptor) {
|
70 | const block = query.type === 'template'
|
71 | ? descriptor.template
|
72 | : query.type === 'script'
|
73 | ? descriptor.script
|
74 | : query.type === 'style'
|
75 | ? descriptor.styles[query.index]
|
76 | : typeof query.index === 'number'
|
77 | ? descriptor.customBlocks[query.index]
|
78 | : null;
|
79 | if (block) {
|
80 | return {
|
81 | code: block.content,
|
82 | map: normalizeSourceMap(block.map),
|
83 | };
|
84 | }
|
85 | }
|
86 | }
|
87 | return undefined;
|
88 | },
|
89 | async transform(code, id) {
|
90 | const query = parseVuePartRequest(id);
|
91 | if (query.vue) {
|
92 | if (!query.src && !filter(query.filename))
|
93 | return null;
|
94 | const descriptor = getDescriptor(query.filename);
|
95 | const hasScoped = descriptor.styles.some((s) => s.scoped);
|
96 | if (query.type === 'template') {
|
97 | debug(`transform(${id})`);
|
98 | const block = descriptor.template;
|
99 | const result = compiler_sfc_1.compileTemplate({
|
100 | filename: query.filename,
|
101 | source: code,
|
102 | inMap: query.src ? undefined : block.map,
|
103 | preprocessLang: block.lang,
|
104 | preprocessCustomRequire: options.preprocessCustomRequire,
|
105 | compiler: options.compiler,
|
106 | ssr: isServer,
|
107 | compilerOptions: {
|
108 | ...options.compilerOptions,
|
109 | scopeId: hasScoped ? `data-v-${query.id}` : undefined,
|
110 | bindingMetadata: descriptor.script
|
111 | ? descriptor.script.bindings
|
112 | : undefined,
|
113 | },
|
114 | transformAssetUrls: options.transformAssetUrls,
|
115 | });
|
116 | if (result.errors.length) {
|
117 | result.errors.forEach((error) => this.error(typeof error === 'string'
|
118 | ? { id: query.filename, message: error }
|
119 | : createRollupError(query.filename, error)));
|
120 | return null;
|
121 | }
|
122 | if (result.tips.length) {
|
123 | result.tips.forEach((tip) => this.warn({
|
124 | id: query.filename,
|
125 | message: tip,
|
126 | }));
|
127 | }
|
128 | return {
|
129 | code: result.code,
|
130 | map: normalizeSourceMap(result.map),
|
131 | };
|
132 | }
|
133 | else if (query.type === 'style') {
|
134 | debug(`transform(${id})`);
|
135 | const block = descriptor.styles[query.index];
|
136 | const result = await compiler_sfc_1.compileStyleAsync({
|
137 | filename: query.filename,
|
138 | id: `data-v-${query.id}`,
|
139 | source: code,
|
140 | scoped: block.scoped,
|
141 | vars: !!block.vars,
|
142 | modules: !!block.module,
|
143 | postcssOptions: options.postcssOptions,
|
144 | postcssPlugins: options.postcssPlugins,
|
145 | modulesOptions: options.cssModulesOptions,
|
146 | preprocessLang: options.preprocessStyles
|
147 | ? block.lang
|
148 | : undefined,
|
149 | preprocessCustomRequire: options.preprocessCustomRequire,
|
150 | preprocessOptions: options.preprocessOptions || {},
|
151 | });
|
152 | if (result.errors.length) {
|
153 | result.errors.forEach((error) => this.error({
|
154 | id: query.filename,
|
155 | message: error.message,
|
156 | }));
|
157 | return null;
|
158 | }
|
159 | if (query.module) {
|
160 | return {
|
161 | code: `export default ${_(result.modules)}`,
|
162 | map: null,
|
163 | };
|
164 | }
|
165 | else {
|
166 | return {
|
167 | code: result.code,
|
168 | map: normalizeSourceMap(result.map),
|
169 | };
|
170 | }
|
171 | }
|
172 | return null;
|
173 | }
|
174 | else if (filter(id)) {
|
175 | debug(`transform(${id})`);
|
176 | const { descriptor, errors } = parseSFC(code, id, rootContext);
|
177 | if (errors.length) {
|
178 | errors.forEach((error) => this.error(createRollupError(id, error)));
|
179 | return null;
|
180 | }
|
181 |
|
182 | const output = transformVueSFC(code, id, descriptor, { rootContext, isProduction, isServer, filterCustomBlock }, options);
|
183 | debug('transient .vue file:', '\n' + output + '\n');
|
184 | return {
|
185 | code: output,
|
186 | map: {
|
187 | mappings: '',
|
188 | },
|
189 | };
|
190 | }
|
191 | else {
|
192 | return null;
|
193 | }
|
194 | },
|
195 | };
|
196 | }
|
197 | exports.default = PluginVue;
|
198 | function createCustomBlockFilter(queries) {
|
199 | if (!queries || queries.length === 0)
|
200 | return () => false;
|
201 | const allowed = new Set(queries.filter((query) => /^[a-z]/i.test(query)));
|
202 | const disallowed = new Set(queries
|
203 | .filter((query) => /^![a-z]/i.test(query))
|
204 | .map((query) => query.substr(1)));
|
205 | const allowAll = queries.includes('*') || !queries.includes('!*');
|
206 | return (type) => {
|
207 | if (allowed.has(type))
|
208 | return true;
|
209 | if (disallowed.has(type))
|
210 | return true;
|
211 | return allowAll;
|
212 | };
|
213 | }
|
214 | function parseVuePartRequest(id) {
|
215 | const [filename, query] = id.split('?', 2);
|
216 | if (!query)
|
217 | return { vue: false, filename };
|
218 | const raw = querystring_1.default.parse(query);
|
219 | if ('vue' in raw) {
|
220 | return {
|
221 | ...raw,
|
222 | filename,
|
223 | vue: true,
|
224 | index: Number(raw.index),
|
225 | src: 'src' in raw,
|
226 | scoped: 'scoped' in raw,
|
227 | };
|
228 | }
|
229 | return { vue: false, filename };
|
230 | }
|
231 | const cache = new Map();
|
232 | function getDescriptor(id) {
|
233 | if (cache.has(id)) {
|
234 | return cache.get(id);
|
235 | }
|
236 | throw new Error(`${id} is not parsed yet`);
|
237 | }
|
238 | function parseSFC(code, id, sourceRoot) {
|
239 | const { descriptor, errors } = compiler_sfc_1.parse(code, {
|
240 | sourceMap: true,
|
241 | filename: id,
|
242 | sourceRoot: sourceRoot,
|
243 | });
|
244 | cache.set(id, descriptor);
|
245 | return { descriptor, errors };
|
246 | }
|
247 | function transformVueSFC(code, resourcePath, descriptor, { rootContext, isProduction, isServer, filterCustomBlock, }, options) {
|
248 | const shortFilePath = path_1.relative(rootContext, resourcePath)
|
249 | .replace(/^(\.\.[\/\\])+/, '')
|
250 | .replace(/\\/g, '/');
|
251 | const id = hash_sum_1.default(isProduction ? shortFilePath + '\n' + code : shortFilePath);
|
252 |
|
253 | const hasScoped = descriptor.styles.some((s) => s.scoped);
|
254 | const templateImport = getTemplateCode(descriptor, resourcePath, id, hasScoped, isServer);
|
255 | const scriptImport = getScriptCode(descriptor, resourcePath);
|
256 | const stylesCode = getStyleCode(descriptor, resourcePath, id, options.preprocessStyles);
|
257 | const customBlocksCode = getCustomBlock(descriptor, resourcePath, filterCustomBlock);
|
258 | const output = [
|
259 | scriptImport,
|
260 | templateImport,
|
261 | stylesCode,
|
262 | customBlocksCode,
|
263 | isServer ? `script.ssrRender = ssrRender` : `script.render = render`,
|
264 | ];
|
265 | if (hasScoped) {
|
266 | output.push(`script.__scopeId = ${_(`data-v-${id}`)}`);
|
267 | }
|
268 | if (!isProduction) {
|
269 | output.push(`script.__file = ${_(shortFilePath)}`);
|
270 | }
|
271 | else if (options.exposeFilename) {
|
272 | output.push(`script.__file = ${_(path_1.basename(shortFilePath))}`);
|
273 | }
|
274 | output.push('export default script');
|
275 | return output.join('\n');
|
276 | }
|
277 | function getTemplateCode(descriptor, resourcePath, id, hasScoped, isServer) {
|
278 | let templateImport = `const render = () => {}`;
|
279 | let templateRequest;
|
280 | if (descriptor.template) {
|
281 | const src = descriptor.template.src || resourcePath;
|
282 | const idQuery = `&id=${id}`;
|
283 | const scopedQuery = hasScoped ? `&scoped=true` : ``;
|
284 | const srcQuery = descriptor.template.src ? `&src` : ``;
|
285 | const attrsQuery = attrsToQuery(descriptor.template.attrs);
|
286 | const query = `?vue&type=template${idQuery}${srcQuery}${scopedQuery}${attrsQuery}`;
|
287 | templateRequest = _(src + query);
|
288 | templateImport = `import { ${isServer ? 'ssrRender' : 'render'} } from ${templateRequest}`;
|
289 | }
|
290 | return templateImport;
|
291 | }
|
292 | function getScriptCode(descriptor, resourcePath) {
|
293 | let scriptImport = `const script = {}`;
|
294 | if (descriptor.script || descriptor.scriptSetup) {
|
295 | descriptor.script = compiler_sfc_1.compileScript(descriptor);
|
296 | const src = descriptor.script.src || resourcePath;
|
297 | const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js');
|
298 | const srcQuery = descriptor.script.src ? `&src` : ``;
|
299 | const query = `?vue&type=script${srcQuery}${attrsQuery}`;
|
300 | const scriptRequest = _(src + query);
|
301 | scriptImport =
|
302 | `import script from ${scriptRequest}\n` + `export * from ${scriptRequest}`;
|
303 | }
|
304 | return scriptImport;
|
305 | }
|
306 | function getStyleCode(descriptor, resourcePath, id, preprocessStyles) {
|
307 | let stylesCode = ``;
|
308 | let hasCSSModules = false;
|
309 | if (descriptor.styles.length) {
|
310 | descriptor.styles.forEach((style, i) => {
|
311 | const src = style.src || resourcePath;
|
312 |
|
313 |
|
314 | const attrsQuery = attrsToQuery(style.attrs, 'css', preprocessStyles);
|
315 | const attrsQueryWithoutModule = attrsQuery.replace(/&module(=true|=[^&]+)?/, '');
|
316 |
|
317 |
|
318 | const idQuery = style.scoped ? `&id=${id}` : ``;
|
319 | const srcQuery = style.src ? `&src` : ``;
|
320 | const query = `?vue&type=style&index=${i}${srcQuery}${idQuery}`;
|
321 | const styleRequest = src + query + attrsQuery;
|
322 | const styleRequestWithoutModule = src + query + attrsQueryWithoutModule;
|
323 | if (style.module) {
|
324 | if (!hasCSSModules) {
|
325 | stylesCode += `\nconst cssModules = script.__cssModules = {}`;
|
326 | hasCSSModules = true;
|
327 | }
|
328 | stylesCode += genCSSModulesCode(id, i, styleRequest, styleRequestWithoutModule, style.module);
|
329 | }
|
330 | else {
|
331 | stylesCode += `\nimport ${_(styleRequest)}`;
|
332 | }
|
333 |
|
334 | });
|
335 | }
|
336 | return stylesCode;
|
337 | }
|
338 | function getCustomBlock(descriptor, resourcePath, filter) {
|
339 | let code = '';
|
340 | descriptor.customBlocks.forEach((block, index) => {
|
341 | if (filter(block.type)) {
|
342 | const src = block.src || resourcePath;
|
343 | const attrsQuery = attrsToQuery(block.attrs, block.type);
|
344 | const srcQuery = block.src ? `&src` : ``;
|
345 | const query = `?vue&type=${block.type}&index=${index}${srcQuery}${attrsQuery}`;
|
346 | const request = _(src + query);
|
347 | code += `import block${index} from ${request}\n`;
|
348 | code += `if (typeof block${index} === 'function') block${index}(script)\n`;
|
349 | }
|
350 | });
|
351 | return code;
|
352 | }
|
353 | function createRollupError(id, error) {
|
354 | return {
|
355 | id,
|
356 | plugin: 'vue',
|
357 | pluginCode: String(error.code),
|
358 | message: error.message,
|
359 | frame: error.loc.source,
|
360 | parserError: error,
|
361 | loc: error.loc
|
362 | ? {
|
363 | file: id,
|
364 | line: error.loc.start.line,
|
365 | column: error.loc.start.column,
|
366 | }
|
367 | : undefined,
|
368 | };
|
369 | }
|
370 |
|
371 |
|
372 | const ignoreList = ['id', 'index', 'src', 'type', 'lang'];
|
373 | function attrsToQuery(attrs, langFallback, forceLangFallback = false) {
|
374 | let query = ``;
|
375 | for (const name in attrs) {
|
376 | const value = attrs[name];
|
377 | if (!ignoreList.includes(name)) {
|
378 | query += `&${querystring_1.default.escape(name)}${value ? `=${querystring_1.default.escape(String(value))}` : ``}`;
|
379 | }
|
380 | }
|
381 | if (langFallback || attrs.lang) {
|
382 | query +=
|
383 | `lang` in attrs
|
384 | ? forceLangFallback
|
385 | ? `&lang.${langFallback}`
|
386 | : `&lang.${attrs.lang}`
|
387 | : `&lang.${langFallback}`;
|
388 | }
|
389 | return query;
|
390 | }
|
391 | function _(any) {
|
392 | return JSON.stringify(any);
|
393 | }
|
394 | function normalizeSourceMap(map) {
|
395 | if (!map)
|
396 | return null;
|
397 | return {
|
398 | ...map,
|
399 | version: Number(map.version),
|
400 | mappings: typeof map.mappings === 'string' ? map.mappings : '',
|
401 | };
|
402 | }
|
403 | function genCSSModulesCode(
|
404 | // @ts-ignore
|
405 | id, index, request, requestWithoutModule, moduleName) {
|
406 | const styleVar = `style${index}`;
|
407 | let code =
|
408 |
|
409 | `\nimport ${_(requestWithoutModule)}` +
|
410 |
|
411 | `\nimport ${styleVar} from ${_(request + '.js')}`;
|
412 |
|
413 | const name = typeof moduleName === 'string' ? moduleName : '$style';
|
414 | code += `\ncssModules["${name}"] = ${styleVar}`;
|
415 | return code;
|
416 | }
|
417 |
|
418 | module.exports = PluginVue;
|