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