"use strict";
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
if (k2 === undefined) k2 = k;
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
}
|
Object.defineProperty(o, k2, desc);
|
}) : (function(o, m, k, k2) {
|
if (k2 === undefined) k2 = k;
|
o[k2] = m[k];
|
}));
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
}) : function(o, v) {
|
o["default"] = v;
|
});
|
var __importStar = (this && this.__importStar) || function (mod) {
|
if (mod && mod.__esModule) return mod;
|
var result = {};
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
__setModuleDefault(result, mod);
|
return result;
|
};
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
};
|
Object.defineProperty(exports, "__esModule", { value: true });
|
exports.hoistAtRules = exports.minifyCSS = exports.importCssRE = exports.cssDataUriRE = exports.cssUrlRE = exports.formatPostcssSourceMap = exports.cssPostPlugin = exports.cssPlugin = exports.isDirectCSSRequest = exports.isCSSRequest = exports.commonjsProxyRE = exports.cssLangRE = void 0;
|
const fs_1 = __importDefault(require("fs"));
|
const path_1 = __importDefault(require("path"));
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
const picocolors_1 = __importDefault(require("picocolors"));
|
const postcss_load_config_1 = __importDefault(require("postcss-load-config"));
|
const pluginutils_1 = require("@rollup/pluginutils");
|
const utils_1 = require("../utils");
|
const asset_1 = require("./asset");
|
const magic_string_1 = __importDefault(require("magic-string"));
|
const esbuild_1 = require("esbuild");
|
const preprocess_1 = require("../../../../preprocess");
|
const constants_1 = require("../../../../constants");
|
const cleanString_1 = require("../cleanString");
|
const shared_1 = require("@vue/shared");
|
const cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)`;
|
exports.cssLangRE = new RegExp(cssLangs);
|
const cssModuleRE = new RegExp(`\\.module${cssLangs}`);
|
const directRequestRE = /(\?|&)direct\b/;
|
exports.commonjsProxyRE = /\?commonjs-proxy/;
|
const varRE = /^var\(/i;
|
const isCSSRequest = (request) => exports.cssLangRE.test(request) && !directRequestRE.test(request);
|
exports.isCSSRequest = isCSSRequest;
|
const isDirectCSSRequest = (request) => exports.cssLangRE.test(request) && directRequestRE.test(request);
|
exports.isDirectCSSRequest = isDirectCSSRequest;
|
const cssModulesCache = new WeakMap();
|
const postcssConfigCache = new WeakMap();
|
/**
|
* Plugin applied before user plugins
|
*/
|
function cssPlugin(config) {
|
let server;
|
let moduleCache;
|
const resolveUrl = config.createResolver({
|
preferRelative: true,
|
tryIndex: false,
|
extensions: [],
|
});
|
const atImportResolvers = createCSSResolvers(config);
|
return {
|
name: 'vite:css',
|
configureServer(_server) {
|
server = _server;
|
},
|
buildStart() {
|
// Ensure a new cache for every build (i.e. rebuilding in watch mode)
|
moduleCache = new Map();
|
cssModulesCache.set(config, moduleCache);
|
},
|
async transform(raw, id) {
|
if (!exports.cssLangRE.test(id) || exports.commonjsProxyRE.test(id)) {
|
return;
|
}
|
const urlReplacer = async (url, importer) => {
|
if (url.startsWith('/') && !url.startsWith('//')) {
|
// /static/logo.png => @/static/logo.png
|
url = '@' + url;
|
}
|
const resolved = await resolveUrl(url, importer);
|
if (resolved) {
|
return (0, asset_1.fileToUrl)(resolved, config, this, true);
|
}
|
return url;
|
};
|
const { code: css, modules, deps, } = await compileCSS(id, raw, config, urlReplacer, atImportResolvers, server);
|
if (modules) {
|
moduleCache.set(id, modules);
|
}
|
// track deps for build watch mode
|
if (config.command === 'build' && config.build.watch && deps) {
|
for (const file of deps) {
|
this.addWatchFile(file);
|
}
|
}
|
return {
|
code: css,
|
// TODO CSS source map
|
map: { mappings: '' },
|
};
|
},
|
};
|
}
|
exports.cssPlugin = cssPlugin;
|
function findCssModuleIds(moduleId, cssModuleIds, seen) {
|
if (!cssModuleIds) {
|
cssModuleIds = new Set();
|
}
|
if (!seen) {
|
seen = new Set();
|
}
|
if (seen.has(moduleId)) {
|
return cssModuleIds;
|
}
|
seen.add(moduleId);
|
const moduleInfo = this.getModuleInfo(moduleId);
|
if (moduleInfo) {
|
moduleInfo.importedIds.forEach((id) => {
|
if (id.includes(constants_1.PAGES_JSON_JS)) {
|
// 查询main.js时,需要忽略pages.json.js,否则会把所有页面样式加进来
|
return;
|
}
|
if (exports.cssLangRE.test(id) && !exports.commonjsProxyRE.test(id)) {
|
cssModuleIds.add(id);
|
}
|
else {
|
findCssModuleIds.call(this, id, cssModuleIds, seen);
|
}
|
});
|
}
|
return cssModuleIds;
|
}
|
/**
|
* Plugin applied after user plugins
|
*/
|
function cssPostPlugin(config, { chunkCssFilename, chunkCssCode, }) {
|
// styles initialization in buildStart causes a styling loss in watch
|
const styles = new Map();
|
let cssChunks;
|
return {
|
name: 'vite:css-post',
|
buildStart() {
|
cssChunks = new Map();
|
},
|
async transform(css, id) {
|
if (!exports.cssLangRE.test(id) || exports.commonjsProxyRE.test(id)) {
|
return;
|
}
|
const modules = cssModulesCache.get(config).get(id);
|
const modulesCode = modules && (0, pluginutils_1.dataToEsm)(modules, { namedExports: true, preferConst: true });
|
// build CSS handling ----------------------------------------------------
|
styles.set(id, css);
|
return {
|
code: modulesCode || '',
|
map: { mappings: '' },
|
// avoid the css module from being tree-shaken so that we can retrieve
|
// it in renderChunk()
|
moduleSideEffects: 'no-treeshake',
|
};
|
},
|
async generateBundle() {
|
const moduleIds = Array.from(this.getModuleIds());
|
moduleIds.forEach((id) => {
|
const filename = chunkCssFilename(id);
|
if (filename) {
|
cssChunks.set(filename, findCssModuleIds.call(this, id));
|
}
|
});
|
if (!cssChunks.size) {
|
return;
|
}
|
// resolve asset URL placeholders to their built file URLs and perform
|
// minification if necessary
|
const processChunkCSS = async (css, { filename, inlined, minify, }) => {
|
// replace asset url references with resolved url.
|
css = css.replace(asset_1.assetUrlRE, (_, fileHash, postfix = '') => {
|
return (0, utils_1.normalizePath)(path_1.default.relative(path_1.default.dirname(filename), (0, asset_1.getAssetFilename)(fileHash, config) + postfix));
|
});
|
// only external @imports and @charset should exist at this point
|
// hoist them to the top of the CSS chunk per spec (#1845 and #6333)
|
if (css.includes('@import') || css.includes('@charset')) {
|
css = await hoistAtRules(css);
|
}
|
if (minify && config.build.minify) {
|
css = await minifyCSS(css, config);
|
}
|
// 压缩后再处理,小程序平台会补充 @import nvue 代码,esbuild 的压缩会把 `@import "./nvue.css";` 的空格移除,变成 `@import"./nvue.css";` 在支付宝小程序中不支持
|
return chunkCssCode(filename, css);
|
};
|
const genCssCode = (fileName) => {
|
return [...cssChunks.get(fileName)]
|
.map((id) => styles.get(id) || '')
|
.join('\n');
|
};
|
for (const filename of cssChunks.keys()) {
|
const cssCode = genCssCode(filename);
|
let source = await processChunkCSS(cssCode, {
|
filename: filename,
|
inlined: false,
|
minify: true,
|
});
|
this.emitFile({
|
fileName: filename,
|
type: 'asset',
|
source,
|
});
|
}
|
},
|
};
|
}
|
exports.cssPostPlugin = cssPostPlugin;
|
function createCSSResolvers(config) {
|
let cssResolve;
|
let sassResolve;
|
let lessResolve;
|
return {
|
get css() {
|
return (cssResolve ||
|
(cssResolve = config.createResolver({
|
extensions: ['.css'],
|
mainFields: ['style'],
|
tryIndex: false,
|
preferRelative: true,
|
})));
|
},
|
get sass() {
|
return (sassResolve ||
|
(sassResolve = config.createResolver({
|
extensions: ['.scss', '.sass', '.css'],
|
mainFields: ['sass', 'style'],
|
tryIndex: true,
|
tryPrefix: '_',
|
preferRelative: true,
|
})));
|
},
|
get less() {
|
return (lessResolve ||
|
(lessResolve = config.createResolver({
|
extensions: ['.less', '.css'],
|
mainFields: ['less', 'style'],
|
tryIndex: false,
|
preferRelative: true,
|
})));
|
},
|
};
|
}
|
function getCssResolversKeys(resolvers) {
|
return Object.keys(resolvers);
|
}
|
async function compileCSS(id, code, config, urlReplacer, atImportResolvers, server) {
|
var _a;
|
const { modules: modulesOptions, preprocessorOptions, devSourcemap, } = config.css || {};
|
const isModule = modulesOptions !== false && cssModuleRE.test(id);
|
// although at serve time it can work without processing, we do need to
|
// crawl them in order to register watch dependencies.
|
const needInlineImport = code.includes('@import');
|
const hasUrl = exports.cssUrlRE.test(code) || cssImageSetRE.test(code);
|
const postcssConfig = await resolvePostcssConfig(config);
|
const lang = (_a = id.match(exports.cssLangRE)) === null || _a === void 0 ? void 0 : _a[1];
|
// 1. plain css that needs no processing
|
if (lang === 'css' &&
|
!postcssConfig &&
|
!isModule &&
|
!needInlineImport &&
|
!hasUrl) {
|
return { code, map: null };
|
}
|
let preprocessorMap;
|
let modules;
|
const deps = new Set();
|
// 2. pre-processors: sass etc.
|
if (isPreProcessor(lang)) {
|
const preProcessor = preProcessors[lang];
|
let opts = (preprocessorOptions && preprocessorOptions[lang]) || {};
|
// support @import from node dependencies by default
|
switch (lang) {
|
case "scss" /* PreprocessLang.scss */:
|
case "sass" /* PreprocessLang.sass */:
|
opts = {
|
includePaths: ['node_modules'],
|
alias: config.resolve.alias,
|
...opts,
|
};
|
break;
|
case "less" /* PreprocessLang.less */:
|
case "styl" /* PreprocessLang.styl */:
|
case "stylus" /* PreprocessLang.stylus */:
|
opts = {
|
paths: ['node_modules'],
|
alias: config.resolve.alias,
|
...opts,
|
};
|
}
|
// important: set this for relative import resolving
|
opts.filename = (0, utils_1.cleanUrl)(id);
|
opts.enableSourcemap = devSourcemap !== null && devSourcemap !== void 0 ? devSourcemap : false;
|
const preprocessResult = await preProcessor(code, config.root, opts, atImportResolvers, !!config.nvue);
|
if (preprocessResult.errors.length) {
|
throw preprocessResult.errors[0];
|
}
|
// TODO 升级
|
// if (preprocessResult.error) {
|
// throw preprocessResult.error
|
// }
|
code = preprocessResult.code;
|
preprocessorMap = combineSourcemapsIfExists(opts.filename, preprocessResult.map, preprocessResult.additionalMap);
|
if (preprocessResult.deps) {
|
preprocessResult.deps.forEach((dep) => {
|
// sometimes sass registers the file itself as a dep
|
if ((0, utils_1.normalizePath)(dep) !== (0, utils_1.normalizePath)(opts.filename)) {
|
deps.add(dep);
|
}
|
});
|
}
|
}
|
// 3. postcss
|
const postcssOptions = (postcssConfig && postcssConfig.options) || {};
|
const postcssPlugins = postcssConfig && postcssConfig.plugins ? postcssConfig.plugins.slice() : [];
|
if (needInlineImport) {
|
postcssPlugins.unshift((await Promise.resolve().then(() => __importStar(require('postcss-import')))).default({
|
async resolve(id, basedir) {
|
// const publicFile = checkPublicFile(id, config)
|
// if (publicFile) {
|
// return publicFile
|
// }
|
const resolved = await atImportResolvers.css(id, path_1.default.join(basedir, '*'));
|
if (resolved) {
|
return path_1.default.resolve(resolved);
|
}
|
return id;
|
},
|
}));
|
}
|
postcssPlugins.push(UrlRewritePostcssPlugin({
|
replacer: urlReplacer,
|
}));
|
if (isModule) {
|
postcssPlugins.unshift((await Promise.resolve().then(() => __importStar(require('postcss-modules')))).default({
|
...modulesOptions,
|
getJSON(cssFileName, _modules, outputFileName) {
|
modules = _modules;
|
if (modulesOptions && (0, shared_1.isFunction)(modulesOptions.getJSON)) {
|
modulesOptions.getJSON(cssFileName, _modules, outputFileName);
|
}
|
},
|
async resolve(id) {
|
for (const key of getCssResolversKeys(atImportResolvers)) {
|
const resolved = await atImportResolvers[key](id);
|
if (resolved) {
|
return path_1.default.resolve(resolved);
|
}
|
}
|
return id;
|
},
|
}));
|
}
|
if (!postcssPlugins.length) {
|
return {
|
code,
|
map: preprocessorMap,
|
};
|
}
|
let postcssResult;
|
try {
|
// postcss is an unbundled dep and should be lazy imported
|
postcssResult = await (await Promise.resolve().then(() => __importStar(require('postcss'))))
|
.default(postcssPlugins)
|
.process(code, {
|
...postcssOptions,
|
to: id,
|
from: id,
|
...(devSourcemap
|
? {
|
map: {
|
inline: false,
|
annotation: false,
|
// postcss may return virtual files
|
// we cannot obtain content of them, so this needs to be enabled
|
sourcesContent: true,
|
// when "prev: preprocessorMap", the result map may include duplicate filename in `postcssResult.map.sources`
|
// prev: preprocessorMap,
|
},
|
}
|
: {}),
|
});
|
// record CSS dependencies from @imports
|
for (const message of postcssResult.messages) {
|
if (message.type === 'dependency') {
|
deps.add((0, utils_1.normalizePath)(message.file));
|
}
|
else if (message.type === 'dir-dependency') {
|
// https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md#3-dependencies
|
const { dir, glob: globPattern = '**' } = message;
|
const pattern = (0, utils_1.normalizePath)(path_1.default.resolve(path_1.default.dirname(id), dir)) + `/` + globPattern;
|
const files = fast_glob_1.default.sync(pattern, {
|
ignore: ['**/node_modules/**'],
|
});
|
for (let i = 0; i < files.length; i++) {
|
deps.add(files[i]);
|
}
|
if (server) {
|
// register glob importers so we can trigger updates on file add/remove
|
if (!(id in server._globImporters)) {
|
;
|
server._globImporters[id] = {
|
module: server.moduleGraph.getModuleById(id),
|
importGlobs: [],
|
};
|
}
|
;
|
server._globImporters[id].importGlobs.push({
|
base: config.root,
|
pattern,
|
});
|
}
|
}
|
else if (message.type === 'warning') {
|
let msg = `[vite:css] ${message.text}`;
|
if (message.line && message.column) {
|
msg += `\n${(0, utils_1.generateCodeFrame)(code, {
|
line: message.line,
|
column: message.column,
|
})}`;
|
}
|
config.logger.warn(picocolors_1.default.yellow(msg));
|
}
|
}
|
}
|
catch (e) {
|
e.message = `[postcss] ${e.message}`;
|
e.code = code;
|
e.loc = {
|
column: e.column,
|
line: e.line,
|
};
|
throw e;
|
}
|
if (!devSourcemap) {
|
return {
|
ast: postcssResult,
|
code: postcssResult.css,
|
map: { mappings: '' },
|
modules,
|
deps,
|
};
|
}
|
const rawPostcssMap = postcssResult.map.toJSON();
|
const postcssMap = formatPostcssSourceMap(
|
// version property of rawPostcssMap is declared as string
|
// but actually it is a number
|
rawPostcssMap, (0, utils_1.cleanUrl)(id));
|
return {
|
ast: postcssResult,
|
code: postcssResult.css,
|
map: combineSourcemapsIfExists((0, utils_1.cleanUrl)(id), postcssMap, preprocessorMap),
|
modules,
|
deps,
|
};
|
}
|
function formatPostcssSourceMap(rawMap, file) {
|
const inputFileDir = path_1.default.dirname(file);
|
const sources = rawMap.sources.map((source) => {
|
const cleanSource = (0, utils_1.cleanUrl)(decodeURIComponent(source));
|
// postcss returns virtual files
|
if (/^<.+>$/.test(cleanSource)) {
|
return `\0${cleanSource}`;
|
}
|
return (0, utils_1.normalizePath)(path_1.default.resolve(inputFileDir, cleanSource));
|
});
|
return {
|
file,
|
mappings: rawMap.mappings,
|
names: rawMap.names,
|
sources,
|
sourcesContent: rawMap.sourcesContent,
|
version: rawMap.version,
|
};
|
}
|
exports.formatPostcssSourceMap = formatPostcssSourceMap;
|
function combineSourcemapsIfExists(filename, map1, map2) {
|
return map1 && map2
|
? (0, utils_1.combineSourcemaps)(filename, [
|
// type of version property of ExistingRawSourceMap is number
|
// but it is always 3
|
map1,
|
map2,
|
])
|
: map1;
|
}
|
async function resolvePostcssConfig(config) {
|
var _a;
|
let result = postcssConfigCache.get(config);
|
if (result !== undefined) {
|
return result;
|
}
|
// inline postcss config via vite config
|
const inlineOptions = (_a = config.css) === null || _a === void 0 ? void 0 : _a.postcss;
|
if ((0, utils_1.isObject)(inlineOptions)) {
|
const options = { ...inlineOptions };
|
delete options.plugins;
|
result = {
|
options,
|
plugins: inlineOptions.plugins || [],
|
};
|
}
|
else {
|
const searchPath = (0, shared_1.isString)(inlineOptions) ? inlineOptions : config.root;
|
try {
|
// @ts-ignore
|
result = await (0, postcss_load_config_1.default)({}, searchPath);
|
}
|
catch (e) {
|
if (!/No PostCSS Config found/.test(e.message)) {
|
if (e instanceof Error) {
|
const { name, message, stack } = e;
|
e.name = 'Failed to load PostCSS config';
|
e.message = `Failed to load PostCSS config (searchPath: ${searchPath}): [${name}] ${message}\n${stack}`;
|
e.stack = ''; // add stack to message to retain stack
|
throw e;
|
}
|
else {
|
throw new Error(`Failed to load PostCSS config: ${e}`);
|
}
|
}
|
result = null;
|
}
|
}
|
postcssConfigCache.set(config, result);
|
return result;
|
}
|
// https://drafts.csswg.org/css-syntax-3/#identifier-code-point
|
exports.cssUrlRE = /(?<=^|[^\w\-\u0080-\uffff])url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/;
|
exports.cssDataUriRE = /(?<=^|[^\w\-\u0080-\uffff])data-uri\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/;
|
exports.importCssRE = /@import ('[^']+\.css'|"[^"]+\.css"|[^'")]+\.css)/;
|
const cssImageSetRE = /(?<=image-set\()((?:[\w\-]+\([^\)]*\)|[^)])*)(?=\))/;
|
const UrlRewritePostcssPlugin = (opts) => {
|
if (!opts) {
|
throw new Error('base or replace is required');
|
}
|
return {
|
postcssPlugin: 'vite-url-rewrite',
|
Once(root) {
|
const promises = [];
|
root.walkDecls((declaration) => {
|
const isCssUrl = exports.cssUrlRE.test(declaration.value);
|
const isCssImageSet = cssImageSetRE.test(declaration.value);
|
if (isCssUrl || isCssImageSet) {
|
const replacerForDeclaration = (rawUrl) => {
|
var _a;
|
const importer = (_a = declaration.source) === null || _a === void 0 ? void 0 : _a.input.file;
|
return opts.replacer(rawUrl, importer);
|
};
|
const rewriterToUse = isCssImageSet
|
? rewriteCssImageSet
|
: rewriteCssUrls;
|
promises.push(rewriterToUse(declaration.value, replacerForDeclaration).then((url) => {
|
declaration.value = url;
|
}));
|
}
|
});
|
if (promises.length) {
|
return Promise.all(promises);
|
}
|
},
|
};
|
};
|
UrlRewritePostcssPlugin.postcss = true;
|
function rewriteCssUrls(css, replacer) {
|
return (0, utils_1.asyncReplace)(css, exports.cssUrlRE, async (match) => {
|
const [matched, rawUrl] = match;
|
return await doUrlReplace(rawUrl, matched, replacer);
|
});
|
}
|
function rewriteCssDataUris(css, replacer) {
|
return (0, utils_1.asyncReplace)(css, exports.cssDataUriRE, async (match) => {
|
const [matched, rawUrl] = match;
|
return await doUrlReplace(rawUrl, matched, replacer, 'data-uri');
|
});
|
}
|
function rewriteImportCss(css, replacer) {
|
return (0, utils_1.asyncReplace)(css, exports.importCssRE, async (match) => {
|
const [matched, rawUrl] = match;
|
return await doImportCSSReplace(rawUrl, matched, replacer);
|
});
|
}
|
// TODO: image and cross-fade could contain a "url" that needs to be processed
|
// https://drafts.csswg.org/css-images-4/#image-notation
|
// https://drafts.csswg.org/css-images-4/#cross-fade-function
|
const cssNotProcessedRE = /(gradient|element|cross-fade|image)\(/;
|
async function rewriteCssImageSet(css, replacer) {
|
return await (0, utils_1.asyncReplace)(css, cssImageSetRE, async (match) => {
|
const [, rawUrl] = match;
|
const url = await (0, utils_1.processSrcSet)(rawUrl, async ({ url }) => {
|
// the url maybe url(...)
|
if (exports.cssUrlRE.test(url)) {
|
return await rewriteCssUrls(url, replacer);
|
}
|
if (!cssNotProcessedRE.test(url)) {
|
return await doUrlReplace(url, url, replacer);
|
}
|
return url;
|
});
|
return url;
|
});
|
}
|
async function doUrlReplace(rawUrl, matched, replacer, funcName = 'url') {
|
let wrap = '';
|
const first = rawUrl[0];
|
if (first === `"` || first === `'`) {
|
wrap = first;
|
rawUrl = rawUrl.slice(1, -1);
|
}
|
if ((0, utils_1.isExternalUrl)(rawUrl) ||
|
(0, utils_1.isDataUrl)(rawUrl) ||
|
rawUrl.startsWith('#') ||
|
varRE.test(rawUrl)) {
|
return matched;
|
}
|
const newUrl = await replacer(rawUrl);
|
if (wrap === '' && newUrl !== encodeURI(newUrl)) {
|
// The new url might need wrapping even if the original did not have it, e.g. if a space was added during replacement
|
wrap = "'";
|
}
|
return `${funcName}(${wrap}${newUrl}${wrap})`;
|
}
|
async function doImportCSSReplace(rawUrl, matched, replacer) {
|
let wrap = '';
|
const first = rawUrl[0];
|
if (first === `"` || first === `'`) {
|
wrap = first;
|
rawUrl = rawUrl.slice(1, -1);
|
}
|
if ((0, utils_1.isExternalUrl)(rawUrl) || (0, utils_1.isDataUrl)(rawUrl) || rawUrl.startsWith('#')) {
|
return matched;
|
}
|
return `@import ${wrap}${await replacer(rawUrl)}${wrap}`;
|
}
|
async function minifyCSS(css, config) {
|
try {
|
const { code, warnings } = await (0, esbuild_1.transform)(css, {
|
loader: 'css',
|
minify: true,
|
target: config.build.cssTarget || undefined,
|
});
|
if (warnings.length) {
|
const msgs = await (0, esbuild_1.formatMessages)(warnings, { kind: 'warning' });
|
config.logger.warn(picocolors_1.default.yellow(`warnings when minifying css:\n${msgs.join('\n')}`));
|
}
|
return code;
|
}
|
catch (e) {
|
if (e.errors) {
|
const msgs = await (0, esbuild_1.formatMessages)(e.errors, { kind: 'error' });
|
e.frame = '\n' + msgs.join('\n');
|
e.loc = e.errors[0].location;
|
}
|
throw e;
|
}
|
}
|
exports.minifyCSS = minifyCSS;
|
async function hoistAtRules(css) {
|
const s = new magic_string_1.default(css);
|
const cleanCss = (0, cleanString_1.emptyCssComments)(css);
|
let match;
|
// #1845
|
// CSS @import can only appear at top of the file. We need to hoist all @import
|
// to top when multiple files are concatenated.
|
// match until semicolon that's not in quotes
|
const atImportRE = /@import\s*(?:url\([^\)]*\)|"([^"]|(?<=\\)")*"|'([^']|(?<=\\)')*'|[^;]*).*?;/gm;
|
while ((match = atImportRE.exec(cleanCss))) {
|
s.remove(match.index, match.index + match[0].length);
|
// Use `appendLeft` instead of `prepend` to preserve original @import order
|
s.appendLeft(0, match[0]);
|
}
|
// #6333
|
// CSS @charset must be the top-first in the file, hoist the first to top
|
const atCharsetRE = /@charset\s*(?:"([^"]|(?<=\\)")*"|'([^']|(?<=\\)')*'|[^;]*).*?;/gm;
|
let foundCharset = false;
|
while ((match = atCharsetRE.exec(cleanCss))) {
|
s.remove(match.index, match.index + match[0].length);
|
if (!foundCharset) {
|
s.prepend(match[0]);
|
foundCharset = true;
|
}
|
}
|
return s.toString();
|
}
|
exports.hoistAtRules = hoistAtRules;
|
const loadedPreprocessors = {};
|
function loadPreprocessor(lang, root) {
|
var _a, _b;
|
if (lang in loadedPreprocessors) {
|
return loadedPreprocessors[lang];
|
}
|
try {
|
// Search for the preprocessor in the root directory first, and fall back
|
// to the default require paths.
|
const fallbackPaths = ((_b = (_a = require.resolve).paths) === null || _b === void 0 ? void 0 : _b.call(_a, lang)) || [];
|
const resolved = require.resolve(lang, { paths: [root, ...fallbackPaths] });
|
return (loadedPreprocessors[lang] = require(resolved));
|
}
|
catch (e) {
|
throw new Error(`Preprocessor dependency "${lang}" not found. Did you install it?`);
|
}
|
}
|
// .scss/.sass processor
|
const scss = async (source, root, options, resolvers, isNVue) => {
|
const render = loadPreprocessor("sass" /* PreprocessLang.sass */, root).render;
|
const internalImporter = (url, importer, done) => {
|
resolvers.sass(url, importer).then((resolved) => {
|
if (resolved) {
|
rebaseUrls(resolved, options.filename, options.alias, isNVue)
|
.then((data) => done === null || done === void 0 ? void 0 : done(data))
|
.catch((data) => done === null || done === void 0 ? void 0 : done(data));
|
}
|
else {
|
done === null || done === void 0 ? void 0 : done(null);
|
}
|
});
|
};
|
const importer = [internalImporter];
|
if (options.importer) {
|
(0, shared_1.isArray)(options.importer)
|
? importer.push(...options.importer)
|
: importer.push(options.importer);
|
}
|
const { content: data, map: additionalMap } = await getSource(source, options.filename, options.additionalData, options.enableSourcemap);
|
const finalOptions = {
|
...options,
|
data,
|
file: options.filename,
|
outFile: options.filename,
|
importer,
|
...(options.enableSourcemap
|
? {
|
sourceMap: true,
|
omitSourceMapUrl: true,
|
sourceMapRoot: path_1.default.dirname(options.filename),
|
}
|
: {}),
|
};
|
try {
|
const result = await new Promise((resolve, reject) => {
|
render(finalOptions, (err, res) => {
|
if (err) {
|
reject(err);
|
}
|
else {
|
resolve(res);
|
}
|
});
|
});
|
const deps = result.stats.includedFiles;
|
const map = result.map
|
? JSON.parse(result.map.toString())
|
: undefined;
|
return {
|
code: result.css.toString(),
|
map,
|
additionalMap,
|
errors: [],
|
deps,
|
};
|
}
|
catch (e) {
|
// normalize SASS error
|
e.id = e.file;
|
e.frame = e.formatted;
|
return { code: '', errors: [e], deps: [] };
|
}
|
};
|
const sass = (source, root, options, aliasResolver, isNVue) => scss(source, root, {
|
...options,
|
indentedSyntax: true,
|
}, aliasResolver, isNVue);
|
function preprocessCss(content, isNVue = false) {
|
if (content.includes('#endif')) {
|
return isNVue ? (0, preprocess_1.preNVueCss)(content) : (0, preprocess_1.preCss)(content);
|
}
|
return content;
|
}
|
/**
|
* relative url() inside \@imported sass and less files must be rebased to use
|
* root file as base.
|
*/
|
async function rebaseUrls(file, rootFile, alias, isNVue = false) {
|
file = path_1.default.resolve(file); // ensure os-specific flashes
|
// fixed by xxxxxx 条件编译
|
let contents = preprocessCss(fs_1.default.readFileSync(file, 'utf-8'), isNVue);
|
// in the same dir, no need to rebase
|
const fileDir = path_1.default.dirname(file);
|
const rootDir = path_1.default.dirname(rootFile);
|
if (fileDir === rootDir) {
|
return { file, contents };
|
}
|
// no url()
|
const hasUrls = exports.cssUrlRE.test(contents);
|
// data-uri() calls
|
const hasDataUris = exports.cssDataUriRE.test(contents);
|
// no @import xxx.css
|
const hasImportCss = exports.importCssRE.test(contents);
|
if (!hasUrls && !hasDataUris && !hasImportCss) {
|
return { file, contents };
|
}
|
let rebased;
|
const rebaseFn = (url) => {
|
if (url.startsWith('/'))
|
return url;
|
// match alias, no need to rewrite
|
for (const { find } of alias) {
|
const matches = (0, shared_1.isString)(find) ? url.startsWith(find) : find.test(url);
|
if (matches) {
|
return url;
|
}
|
}
|
const absolute = path_1.default.resolve(fileDir, url);
|
const relative = path_1.default.relative(rootDir, absolute);
|
return (0, utils_1.normalizePath)(relative);
|
};
|
// fix css imports in less such as `@import "foo.css"`
|
if (hasImportCss) {
|
contents = await rewriteImportCss(contents, rebaseFn);
|
}
|
if (hasUrls) {
|
contents = await rewriteCssUrls(rebased || contents, rebaseFn);
|
}
|
if (hasDataUris) {
|
contents = await rewriteCssDataUris(rebased || contents, rebaseFn);
|
}
|
return {
|
file,
|
contents,
|
};
|
}
|
// .less
|
const less = async (source, root, options, resolvers, isNVue) => {
|
const nodeLess = loadPreprocessor("less" /* PreprocessLang.less */, root);
|
const viteResolverPlugin = createViteLessPlugin(nodeLess, options.filename, options.alias, resolvers, isNVue);
|
const { content, map: additionalMap } = await getSource(source, options.filename, options.additionalData, options.enableSourcemap);
|
let result;
|
try {
|
result = await nodeLess.render(content, {
|
...options,
|
plugins: [viteResolverPlugin, ...(options.plugins || [])],
|
...(options.enableSourcemap
|
? {
|
sourceMap: {
|
outputSourceFiles: true,
|
sourceMapFileInline: false,
|
},
|
}
|
: {}),
|
});
|
}
|
catch (e) {
|
const error = e;
|
// normalize error info
|
const normalizedError = new Error(error.message || error.type);
|
normalizedError.loc = {
|
file: error.filename || options.filename,
|
line: error.line,
|
column: error.column,
|
};
|
return { code: '', errors: [normalizedError], deps: [] };
|
}
|
const map = result.map && JSON.parse(result.map);
|
if (map) {
|
delete map.sourcesContent;
|
}
|
return {
|
code: result.css.toString(),
|
map,
|
additionalMap,
|
deps: result.imports,
|
errors: [],
|
};
|
};
|
/**
|
* Less manager, lazy initialized
|
*/
|
let ViteLessManager;
|
function createViteLessPlugin(less, rootFile, alias, resolvers, isNVue) {
|
if (!ViteLessManager) {
|
ViteLessManager = class ViteManager extends less.FileManager {
|
constructor(rootFile, resolvers, alias) {
|
super();
|
this.rootFile = rootFile;
|
this.resolvers = resolvers;
|
this.alias = alias;
|
}
|
supports() {
|
return true;
|
}
|
supportsSync() {
|
return false;
|
}
|
async loadFile(filename, dir, opts, env) {
|
const resolved = await this.resolvers.less(filename, path_1.default.join(dir, '*'));
|
if (resolved) {
|
const result = await rebaseUrls(resolved, this.rootFile, this.alias, isNVue);
|
let contents;
|
if (result && 'contents' in result) {
|
contents = result.contents;
|
}
|
else {
|
contents = fs_1.default.readFileSync(resolved, 'utf-8');
|
}
|
return {
|
filename: path_1.default.resolve(resolved),
|
contents,
|
};
|
}
|
else {
|
return super.loadFile(filename, dir, opts, env);
|
}
|
}
|
};
|
}
|
return {
|
install(_, pluginManager) {
|
pluginManager.addFileManager(new ViteLessManager(rootFile, resolvers, alias));
|
},
|
minVersion: [3, 0, 0],
|
};
|
}
|
// .styl
|
const styl = async (source, root, options) => {
|
var _a;
|
const nodeStylus = loadPreprocessor("stylus" /* PreprocessLang.stylus */, root);
|
// Get source with preprocessor options.additionalData. Make sure a new line separator
|
// is added to avoid any render error, as added stylus content may not have semi-colon separators
|
const { content, map: additionalMap } = await getSource(source, options.filename, options.additionalData, options.enableSourcemap, '\n');
|
// Get preprocessor options.imports dependencies as stylus
|
// does not return them with its builtin `.deps()` method
|
const importsDeps = ((_a = options.imports) !== null && _a !== void 0 ? _a : []).map((dep) => path_1.default.resolve(dep));
|
try {
|
const ref = nodeStylus(content, options);
|
if (options.enableSourcemap) {
|
ref.set('sourcemap', {
|
comment: false,
|
inline: false,
|
basePath: root,
|
});
|
}
|
const result = ref.render();
|
// Concat imports deps with computed deps
|
const deps = [...ref.deps(), ...importsDeps];
|
// @ts-expect-error sourcemap exists
|
const map = ref.sourcemap;
|
return {
|
code: result,
|
map: formatStylusSourceMap(map, root),
|
additionalMap,
|
errors: [],
|
deps,
|
};
|
}
|
catch (e) {
|
return { code: '', errors: [e], deps: [] };
|
}
|
};
|
function formatStylusSourceMap(mapBefore, root) {
|
if (!mapBefore)
|
return undefined;
|
const map = { ...mapBefore };
|
const resolveFromRoot = (p) => (0, utils_1.normalizePath)(path_1.default.resolve(root, p));
|
if (map.file) {
|
map.file = resolveFromRoot(map.file);
|
}
|
map.sources = map.sources.map(resolveFromRoot);
|
return map;
|
}
|
async function getSource(source, filename, additionalData, enableSourcemap, sep = '') {
|
if (!additionalData)
|
return { content: source };
|
if ((0, shared_1.isFunction)(additionalData)) {
|
const newContent = await additionalData(source, filename);
|
if ((0, shared_1.isString)(newContent)) {
|
return { content: newContent };
|
}
|
return newContent;
|
}
|
if (!enableSourcemap) {
|
return { content: additionalData + sep + source };
|
}
|
const ms = new magic_string_1.default(source);
|
ms.appendLeft(0, sep);
|
ms.appendLeft(0, additionalData);
|
const map = ms.generateMap({ hires: true });
|
map.file = filename;
|
map.sources = [filename];
|
return {
|
content: ms.toString(),
|
map,
|
};
|
}
|
const preProcessors = Object.freeze({
|
["less" /* PreprocessLang.less */]: less,
|
["sass" /* PreprocessLang.sass */]: sass,
|
["scss" /* PreprocessLang.scss */]: scss,
|
["styl" /* PreprocessLang.styl */]: styl,
|
["stylus" /* PreprocessLang.stylus */]: styl,
|
});
|
function isPreProcessor(lang) {
|
return lang && lang in preProcessors;
|
}
|