mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-08 01:17:23 +08:00
479 lines
19 KiB
JavaScript
479 lines
19 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
try {
|
|
require.resolve('@vue/compiler-sfc');
|
|
}
|
|
catch (e) {
|
|
throw new Error('rollup-plugin-vue requires @vue/compiler-sfc to be present in the dependency ' +
|
|
'tree.');
|
|
}
|
|
const compiler_sfc_1 = require("@vue/compiler-sfc");
|
|
const fs_1 = __importDefault(require("fs"));
|
|
const debug_1 = __importDefault(require("debug"));
|
|
const hash_sum_1 = __importDefault(require("hash-sum"));
|
|
const path_1 = require("path");
|
|
const querystring_1 = __importDefault(require("querystring"));
|
|
const rollup_pluginutils_1 = require("rollup-pluginutils");
|
|
const debug = debug_1.default('rollup-plugin-vue');
|
|
const defaultOptions = {
|
|
include: /\.vue$/,
|
|
exclude: [],
|
|
target: 'browser',
|
|
exposeFilename: false,
|
|
customBlocks: [],
|
|
};
|
|
function PluginVue(userOptions = {}) {
|
|
const options = {
|
|
...defaultOptions,
|
|
...userOptions,
|
|
};
|
|
const isServer = options.target === 'node';
|
|
const isProduction = process.env.NODE_ENV === 'production' || process.env.BUILD === 'production';
|
|
const rootContext = process.cwd();
|
|
const filter = rollup_pluginutils_1.createFilter(options.include, options.exclude);
|
|
const filterCustomBlock = createCustomBlockFilter(options.customBlocks);
|
|
return {
|
|
name: 'vue',
|
|
async resolveId(id, importer) {
|
|
const query = parseVuePartRequest(id);
|
|
if (query.vue) {
|
|
if (query.src) {
|
|
const resolved = await this.resolve(query.filename, importer, {
|
|
skipSelf: true,
|
|
});
|
|
if (resolved) {
|
|
cache.set(resolved.id, getDescriptor(importer));
|
|
const [, originalQuery] = id.split('?', 2);
|
|
resolved.id += `?${originalQuery}`;
|
|
return resolved;
|
|
}
|
|
}
|
|
else if (!filter(query.filename)) {
|
|
return undefined;
|
|
}
|
|
debug(`resolveId(${id})`);
|
|
return id;
|
|
}
|
|
return undefined;
|
|
},
|
|
load(id) {
|
|
const query = parseVuePartRequest(id);
|
|
if (query.vue) {
|
|
if (query.src) {
|
|
return fs_1.default.readFileSync(query.filename, 'utf-8');
|
|
}
|
|
const descriptor = getDescriptor(query.filename);
|
|
if (descriptor) {
|
|
const block = query.type === 'template'
|
|
? descriptor.template
|
|
: query.type === 'script'
|
|
? descriptor.script
|
|
: query.type === 'style'
|
|
? descriptor.styles[query.index]
|
|
: typeof query.index === 'number'
|
|
? descriptor.customBlocks[query.index]
|
|
: null;
|
|
if (block) {
|
|
return {
|
|
code: block.content,
|
|
map: normalizeSourceMap(block.map, id),
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
},
|
|
async transform(code, id) {
|
|
const query = parseVuePartRequest(id);
|
|
if (query.vue) {
|
|
if (!query.src && !filter(query.filename))
|
|
return null;
|
|
const descriptor = getDescriptor(query.filename);
|
|
const hasScoped = descriptor.styles.some((s) => s.scoped);
|
|
if (query.src) {
|
|
this.addWatchFile(query.filename);
|
|
}
|
|
if (query.type === 'template') {
|
|
debug(`transform(${id})`);
|
|
const block = descriptor.template;
|
|
const preprocessLang = block.lang;
|
|
const preprocessOptions = preprocessLang &&
|
|
options.templatePreprocessOptions &&
|
|
options.templatePreprocessOptions[preprocessLang];
|
|
const result = compiler_sfc_1.compileTemplate({
|
|
filename: query.filename,
|
|
source: code,
|
|
inMap: query.src ? undefined : block.map,
|
|
preprocessLang,
|
|
preprocessOptions,
|
|
preprocessCustomRequire: options.preprocessCustomRequire,
|
|
compiler: options.compiler,
|
|
ssr: isServer,
|
|
compilerOptions: {
|
|
...options.compilerOptions,
|
|
scopeId: hasScoped ? `data-v-${query.id}` : undefined,
|
|
bindingMetadata: descriptor.script
|
|
? descriptor.script.bindings
|
|
: undefined,
|
|
},
|
|
transformAssetUrls: options.transformAssetUrls,
|
|
});
|
|
if (result.errors.length) {
|
|
result.errors.forEach((error) => this.error(typeof error === 'string'
|
|
? { id: query.filename, message: error }
|
|
: createRollupError(query.filename, error)));
|
|
return null;
|
|
}
|
|
if (result.tips.length) {
|
|
result.tips.forEach((tip) => this.warn({
|
|
id: query.filename,
|
|
message: tip,
|
|
}));
|
|
}
|
|
return {
|
|
code: result.code,
|
|
map: normalizeSourceMap(result.map, id),
|
|
};
|
|
}
|
|
else if (query.type === 'style') {
|
|
debug(`transform(${id})`);
|
|
const block = descriptor.styles[query.index];
|
|
let preprocessOptions = options.preprocessOptions || {};
|
|
const preprocessLang = (options.preprocessStyles
|
|
? block.lang
|
|
: undefined);
|
|
if (preprocessLang) {
|
|
preprocessOptions =
|
|
preprocessOptions[preprocessLang] || preprocessOptions;
|
|
// include node_modules for imports by default
|
|
switch (preprocessLang) {
|
|
case 'scss':
|
|
case 'sass':
|
|
preprocessOptions = {
|
|
includePaths: ['node_modules'],
|
|
...preprocessOptions,
|
|
};
|
|
break;
|
|
case 'less':
|
|
case 'stylus':
|
|
preprocessOptions = {
|
|
paths: ['node_modules'],
|
|
...preprocessOptions,
|
|
};
|
|
}
|
|
}
|
|
else {
|
|
preprocessOptions = {};
|
|
}
|
|
const result = await compiler_sfc_1.compileStyleAsync({
|
|
filename: query.filename,
|
|
id: `data-v-${query.id}`,
|
|
source: code,
|
|
scoped: block.scoped,
|
|
vars: !!block.vars,
|
|
modules: !!block.module,
|
|
postcssOptions: options.postcssOptions,
|
|
postcssPlugins: options.postcssPlugins,
|
|
modulesOptions: options.cssModulesOptions,
|
|
preprocessLang,
|
|
preprocessCustomRequire: options.preprocessCustomRequire,
|
|
preprocessOptions,
|
|
});
|
|
if (result.errors.length) {
|
|
result.errors.forEach((error) => this.error({
|
|
id: query.filename,
|
|
message: error.message,
|
|
}));
|
|
return null;
|
|
}
|
|
if (query.module) {
|
|
return {
|
|
code: `export default ${_(result.modules)}`,
|
|
map: null,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
code: result.code,
|
|
map: normalizeSourceMap(result.map, id),
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
else if (filter(id)) {
|
|
debug(`transform(${id})`);
|
|
const { descriptor, errors } = parseSFC(code, id, rootContext);
|
|
if (errors.length) {
|
|
errors.forEach((error) => this.error(createRollupError(id, error)));
|
|
return null;
|
|
}
|
|
// module id for scoped CSS & hot-reload
|
|
const output = transformVueSFC(code, id, descriptor, { rootContext, isProduction, isServer, filterCustomBlock }, options);
|
|
debug('transient .vue file:', '\n' + output + '\n');
|
|
return {
|
|
code: output,
|
|
map: {
|
|
mappings: '',
|
|
},
|
|
};
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
},
|
|
};
|
|
}
|
|
exports.default = PluginVue;
|
|
function createCustomBlockFilter(queries) {
|
|
if (!queries || queries.length === 0)
|
|
return () => false;
|
|
const allowed = new Set(queries.filter((query) => /^[a-z]/i.test(query)));
|
|
const disallowed = new Set(queries
|
|
.filter((query) => /^![a-z]/i.test(query))
|
|
.map((query) => query.substr(1)));
|
|
const allowAll = queries.includes('*') || !queries.includes('!*');
|
|
return (type) => {
|
|
if (allowed.has(type))
|
|
return true;
|
|
if (disallowed.has(type))
|
|
return true;
|
|
return allowAll;
|
|
};
|
|
}
|
|
function parseVuePartRequest(id) {
|
|
const [filename, query] = id.split('?', 2);
|
|
if (!query)
|
|
return { vue: false, filename };
|
|
const raw = querystring_1.default.parse(query);
|
|
if ('vue' in raw) {
|
|
return {
|
|
...raw,
|
|
filename,
|
|
vue: true,
|
|
index: Number(raw.index),
|
|
src: 'src' in raw,
|
|
scoped: 'scoped' in raw,
|
|
};
|
|
}
|
|
return { vue: false, filename };
|
|
}
|
|
const cache = new Map();
|
|
function getDescriptor(id) {
|
|
if (cache.has(id)) {
|
|
return cache.get(id);
|
|
}
|
|
throw new Error(`${id} is not parsed yet`);
|
|
}
|
|
function parseSFC(code, id, sourceRoot) {
|
|
const { descriptor, errors } = compiler_sfc_1.parse(code, {
|
|
sourceMap: true,
|
|
filename: id,
|
|
sourceRoot: sourceRoot,
|
|
});
|
|
cache.set(id, descriptor);
|
|
return { descriptor, errors: errors };
|
|
}
|
|
function transformVueSFC(code, resourcePath, descriptor, { rootContext, isProduction, isServer, filterCustomBlock, }, options) {
|
|
const shortFilePath = path_1.relative(rootContext, resourcePath)
|
|
.replace(/^(\.\.[\/\\])+/, '')
|
|
.replace(/\\/g, '/');
|
|
const id = hash_sum_1.default(isProduction ? shortFilePath + '\n' + code : shortFilePath);
|
|
// feature information
|
|
const hasScoped = descriptor.styles.some((s) => s.scoped);
|
|
const templateImport = !descriptor.template
|
|
? ''
|
|
: getTemplateCode(descriptor, resourcePath, id, hasScoped, isServer);
|
|
const renderReplace = !descriptor.template
|
|
? ''
|
|
: isServer
|
|
? `script.ssrRender = ssrRender`
|
|
: `script.render = render`;
|
|
const scriptImport = getScriptCode(descriptor, resourcePath);
|
|
const stylesCode = getStyleCode(descriptor, resourcePath, id, options.preprocessStyles);
|
|
const customBlocksCode = getCustomBlock(descriptor, resourcePath, filterCustomBlock);
|
|
const output = [
|
|
scriptImport,
|
|
templateImport,
|
|
stylesCode,
|
|
customBlocksCode,
|
|
renderReplace,
|
|
];
|
|
if (hasScoped) {
|
|
output.push(`script.__scopeId = ${_(`data-v-${id}`)}`);
|
|
}
|
|
if (!isProduction) {
|
|
output.push(`script.__file = ${_(shortFilePath)}`);
|
|
}
|
|
else if (options.exposeFilename) {
|
|
output.push(`script.__file = ${_(path_1.basename(shortFilePath))}`);
|
|
}
|
|
output.push('export default script');
|
|
return output.join('\n');
|
|
}
|
|
function getTemplateCode(descriptor, resourcePath, id, hasScoped, isServer) {
|
|
const renderFnName = isServer ? 'ssrRender' : 'render';
|
|
let templateImport = `const ${renderFnName} = () => {}`;
|
|
let templateRequest;
|
|
if (descriptor.template) {
|
|
const src = descriptor.template.src || resourcePath;
|
|
const idQuery = `&id=${id}`;
|
|
const scopedQuery = hasScoped ? `&scoped=true` : ``;
|
|
const srcQuery = descriptor.template.src ? `&src` : ``;
|
|
const attrsQuery = attrsToQuery(descriptor.template.attrs, 'js', true);
|
|
const query = `?vue&type=template${idQuery}${srcQuery}${scopedQuery}${attrsQuery}`;
|
|
templateRequest = _(src + query);
|
|
templateImport = `import { ${renderFnName} } from ${templateRequest}`;
|
|
}
|
|
return templateImport;
|
|
}
|
|
function getScriptCode(descriptor, resourcePath) {
|
|
let scriptImport = `const script = {}`;
|
|
if (descriptor.script || descriptor.scriptSetup) {
|
|
if (compiler_sfc_1.compileScript) {
|
|
descriptor.script = compiler_sfc_1.compileScript(descriptor);
|
|
}
|
|
if (descriptor.script) {
|
|
const src = descriptor.script.src || resourcePath;
|
|
const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js');
|
|
const srcQuery = descriptor.script.src ? `&src` : ``;
|
|
const query = `?vue&type=script${srcQuery}${attrsQuery}`;
|
|
const scriptRequest = _(src + query);
|
|
scriptImport =
|
|
`import script from ${scriptRequest}\n` +
|
|
`export * from ${scriptRequest}`; // support named exports
|
|
}
|
|
}
|
|
return scriptImport;
|
|
}
|
|
function getStyleCode(descriptor, resourcePath, id, preprocessStyles) {
|
|
let stylesCode = ``;
|
|
let hasCSSModules = false;
|
|
if (descriptor.styles.length) {
|
|
descriptor.styles.forEach((style, i) => {
|
|
const src = style.src || resourcePath;
|
|
// do not include module in default query, since we use it to indicate
|
|
// that the module needs to export the modules json
|
|
const attrsQuery = attrsToQuery(style.attrs, 'css', preprocessStyles);
|
|
const attrsQueryWithoutModule = attrsQuery.replace(/&module(=true|=[^&]+)?/, '');
|
|
// make sure to only pass id when necessary so that we don't inject
|
|
// duplicate tags when multiple components import the same css file
|
|
const idQuery = style.scoped ? `&id=${id}` : ``;
|
|
const srcQuery = style.src ? `&src` : ``;
|
|
const query = `?vue&type=style&index=${i}${srcQuery}${idQuery}`;
|
|
const styleRequest = src + query + attrsQuery;
|
|
const styleRequestWithoutModule = src + query + attrsQueryWithoutModule;
|
|
if (style.module) {
|
|
if (!hasCSSModules) {
|
|
stylesCode += `\nconst cssModules = script.__cssModules = {}`;
|
|
hasCSSModules = true;
|
|
}
|
|
stylesCode += genCSSModulesCode(id, i, styleRequest, styleRequestWithoutModule, style.module);
|
|
}
|
|
else {
|
|
stylesCode += `\nimport ${_(styleRequest)}`;
|
|
}
|
|
// TODO SSR critical CSS collection
|
|
});
|
|
}
|
|
return stylesCode;
|
|
}
|
|
function getCustomBlock(descriptor, resourcePath, filter) {
|
|
let code = '';
|
|
descriptor.customBlocks.forEach((block, index) => {
|
|
if (filter(block.type)) {
|
|
const src = block.src || resourcePath;
|
|
const attrsQuery = attrsToQuery(block.attrs, block.type);
|
|
const srcQuery = block.src ? `&src` : ``;
|
|
const query = `?vue&type=${block.type}&index=${index}${srcQuery}${attrsQuery}`;
|
|
const request = _(src + query);
|
|
code += `import block${index} from ${request}\n`;
|
|
code += `if (typeof block${index} === 'function') block${index}(script)\n`;
|
|
}
|
|
});
|
|
return code;
|
|
}
|
|
function createRollupError(id, error) {
|
|
if ('code' in error) {
|
|
return {
|
|
id,
|
|
plugin: 'vue',
|
|
pluginCode: String(error.code),
|
|
message: error.message,
|
|
frame: error.loc.source,
|
|
parserError: error,
|
|
loc: error.loc
|
|
? {
|
|
file: id,
|
|
line: error.loc.start.line,
|
|
column: error.loc.start.column,
|
|
}
|
|
: undefined,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
id,
|
|
plugin: 'vue',
|
|
message: error.message,
|
|
parserError: error,
|
|
};
|
|
}
|
|
}
|
|
// these are built-in query parameters so should be ignored
|
|
// if the user happen to add them as attrs
|
|
const ignoreList = ['id', 'index', 'src', 'type', 'lang'];
|
|
function attrsToQuery(attrs, langFallback, forceLangFallback = false) {
|
|
let query = ``;
|
|
for (const name in attrs) {
|
|
const value = attrs[name];
|
|
if (!ignoreList.includes(name)) {
|
|
query += `&${querystring_1.default.escape(name)}${value ? `=${querystring_1.default.escape(String(value))}` : ``}`;
|
|
}
|
|
}
|
|
if (langFallback || attrs.lang) {
|
|
query +=
|
|
`lang` in attrs
|
|
? forceLangFallback
|
|
? `&lang.${langFallback}`
|
|
: `&lang.${attrs.lang}`
|
|
: `&lang.${langFallback}`;
|
|
}
|
|
return query;
|
|
}
|
|
function _(any) {
|
|
return JSON.stringify(any);
|
|
}
|
|
function normalizeSourceMap(map, id) {
|
|
if (!map)
|
|
return null;
|
|
if (!id.includes('type=script')) {
|
|
map.file = id;
|
|
map.sources[0] = id;
|
|
}
|
|
return {
|
|
...map,
|
|
version: Number(map.version),
|
|
mappings: typeof map.mappings === 'string' ? map.mappings : '',
|
|
};
|
|
}
|
|
function genCSSModulesCode(
|
|
// @ts-ignore
|
|
id, index, request, requestWithoutModule, moduleName) {
|
|
const styleVar = `style${index}`;
|
|
let code =
|
|
// first import the CSS for extraction
|
|
`\nimport ${_(requestWithoutModule)}` +
|
|
// then import the json file to expose to component...
|
|
`\nimport ${styleVar} from ${_(request + '.js')}`;
|
|
// inject variable
|
|
const name = typeof moduleName === 'string' ? moduleName : '$style';
|
|
code += `\ncssModules["${name}"] = ${styleVar}`;
|
|
return code;
|
|
}
|
|
// overwrite for cjs require('rollup-plugin-vue')() usage
|
|
module.exports = PluginVue;
|