"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.urlToBuiltUrl = exports.getAssetHash = exports.assetFileNamesToFileName = exports.getAssetFilename = exports.fileToUrl = exports.checkPublicFile = exports.registerAssetToChunk = exports.assetPlugin = exports.chunkToEmittedAssetsMap = exports.assetUrlRE = void 0;
|
const path_1 = __importDefault(require("path"));
|
const url_1 = require("url");
|
const lite_1 = __importDefault(require("mime/lite"));
|
const fs_1 = __importStar(require("fs"));
|
const magic_string_1 = __importDefault(require("magic-string"));
|
const crypto_1 = require("crypto");
|
const utils_1 = require("../utils");
|
const utils_2 = require("../../../../vite/utils/utils");
|
const shared_1 = require("@vue/shared");
|
exports.assetUrlRE = /__VITE_ASSET__([a-z\d]{8})__(?:\$_(.*?)__)?/g;
|
// urls in JS must be quoted as strings, so when replacing them we need
|
// a different regex
|
const assetUrlQuotedRE = /"__VITE_ASSET__([a-z\d]{8})__(?:\$_(.*?)__)?"/g;
|
const rawRE = /(\?|&)raw(?:&|$)/;
|
const urlRE = /(\?|&)url(?:&|$)/;
|
exports.chunkToEmittedAssetsMap = new WeakMap();
|
const assetCache = new WeakMap();
|
const assetHashToFilenameMap = new WeakMap();
|
// save hashes of the files that has been emitted in build watch
|
const emittedHashMap = new WeakMap();
|
/**
|
* Also supports loading plain strings with import text from './foo.txt?raw'
|
*/
|
function assetPlugin(config) {
|
// assetHashToFilenameMap initialization in buildStart causes getAssetFilename to return undefined
|
assetHashToFilenameMap.set(config, new Map());
|
return {
|
name: 'vite:asset',
|
buildStart() {
|
assetCache.set(config, new Map());
|
emittedHashMap.set(config, new Set());
|
},
|
resolveId(id) {
|
if (!config.assetsInclude((0, utils_1.cleanUrl)(id))) {
|
return;
|
}
|
// imports to absolute urls pointing to files in /public
|
// will fail to resolve in the main resolver. handle them here.
|
const publicFile = checkPublicFile(id, config);
|
if (publicFile) {
|
return id;
|
}
|
},
|
async load(id) {
|
if (id.startsWith('\0')) {
|
// Rollup convention, this id should be handled by the
|
// plugin that marked it with \0
|
return;
|
}
|
// raw requests, read from disk
|
if (rawRE.test(id)) {
|
const file = checkPublicFile(id, config) || (0, utils_1.cleanUrl)(id);
|
// raw query, read file and return as string
|
return `export default ${JSON.stringify(await fs_1.promises.readFile(file, 'utf-8'))}`;
|
}
|
if (!config.assetsInclude((0, utils_1.cleanUrl)(id)) && !urlRE.test(id)) {
|
return;
|
}
|
id = id.replace(urlRE, '$1').replace(/[\?&]$/, '');
|
const url = await fileToUrl(id, config, this);
|
return `export default ${JSON.stringify(url)}`;
|
},
|
renderChunk(code, chunk) {
|
let match;
|
let s;
|
while ((match = assetUrlQuotedRE.exec(code))) {
|
s = s || (s = new magic_string_1.default(code));
|
const [full, hash, postfix = ''] = match;
|
// some internal plugins may still need to emit chunks (e.g. worker) so
|
// fallback to this.getFileName for that.
|
const file = getAssetFilename(hash, config) || this.getFileName(hash);
|
registerAssetToChunk(chunk, file);
|
const outputFilepath = config.base + file + postfix;
|
s.overwrite(match.index, match.index + full.length, JSON.stringify(outputFilepath));
|
}
|
if (s) {
|
return {
|
code: s.toString(),
|
map: (0, utils_2.withSourcemap)(config) ? s.generateMap({ hires: true }) : null,
|
};
|
}
|
else {
|
return null;
|
}
|
},
|
};
|
}
|
exports.assetPlugin = assetPlugin;
|
function registerAssetToChunk(chunk, file) {
|
let emitted = exports.chunkToEmittedAssetsMap.get(chunk);
|
if (!emitted) {
|
emitted = new Set();
|
exports.chunkToEmittedAssetsMap.set(chunk, emitted);
|
}
|
emitted.add((0, utils_1.cleanUrl)(file));
|
}
|
exports.registerAssetToChunk = registerAssetToChunk;
|
function checkPublicFile(url, { publicDir }) {
|
// note if the file is in /public, the resolver would have returned it
|
// as-is so it's not going to be a fully resolved path.
|
if (!publicDir || !url.startsWith('/')) {
|
return;
|
}
|
const publicFile = path_1.default.join(publicDir, (0, utils_1.cleanUrl)(url));
|
if (fs_1.default.existsSync(publicFile)) {
|
return publicFile;
|
}
|
else {
|
return;
|
}
|
}
|
exports.checkPublicFile = checkPublicFile;
|
function fileToUrl(id, config, ctx, canInline = false) {
|
return fileToBuiltUrl(id, config, ctx, false, canInline);
|
}
|
exports.fileToUrl = fileToUrl;
|
function getAssetFilename(hash, config) {
|
var _a;
|
return (_a = assetHashToFilenameMap.get(config)) === null || _a === void 0 ? void 0 : _a.get(hash);
|
}
|
exports.getAssetFilename = getAssetFilename;
|
/**
|
* converts the source filepath of the asset to the output filename based on the assetFileNames option. \
|
* this function imitates the behavior of rollup.js. \
|
* https://rollupjs.org/guide/en/#outputassetfilenames
|
*
|
* @example
|
* ```ts
|
* const content = Buffer.from('text');
|
* const fileName = assetFileNamesToFileName(
|
* 'assets/[name].[hash][extname]',
|
* '/path/to/file.txt',
|
* getAssetHash(content),
|
* content
|
* )
|
* // fileName: 'assets/file.982d9e3e.txt'
|
* ```
|
*
|
* @param assetFileNames filename pattern. e.g. `'assets/[name].[hash][extname]'`
|
* @param file filepath of the asset
|
* @param contentHash hash of the asset. used for `'[hash]'` placeholder
|
* @param content content of the asset. passed to `assetFileNames` if `assetFileNames` is a function
|
* @returns output filename
|
*/
|
function assetFileNamesToFileName(assetFileNames, file, contentHash, content) {
|
const basename = path_1.default.basename(file);
|
// placeholders for `assetFileNames`
|
// `hash` is slightly different from the rollup's one
|
const extname = path_1.default.extname(basename);
|
const ext = extname.substring(1);
|
const name = basename.slice(0, -extname.length);
|
const hash = contentHash;
|
if ((0, shared_1.isFunction)(assetFileNames)) {
|
assetFileNames = assetFileNames({
|
name: file,
|
source: content,
|
type: 'asset',
|
});
|
if (!(0, shared_1.isString)(assetFileNames)) {
|
throw new TypeError('assetFileNames must return a string');
|
}
|
}
|
else if (!(0, shared_1.isString)(assetFileNames)) {
|
throw new TypeError('assetFileNames must be a string or a function');
|
}
|
const fileName = assetFileNames.replace(/\[\w+\]/g, (placeholder) => {
|
switch (placeholder) {
|
case '[ext]':
|
return ext;
|
case '[extname]':
|
return extname;
|
case '[hash]':
|
return hash;
|
case '[name]':
|
return sanitizeFileName(name);
|
}
|
throw new Error(`invalid placeholder ${placeholder} in assetFileNames "${assetFileNames}"`);
|
});
|
return fileName;
|
}
|
exports.assetFileNamesToFileName = assetFileNamesToFileName;
|
// taken from https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/utils/sanitizeFileName.ts
|
// https://datatracker.ietf.org/doc/html/rfc2396
|
// eslint-disable-next-line no-control-regex
|
const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g;
|
const DRIVE_LETTER_REGEX = /^[a-z]:/i;
|
function sanitizeFileName(name) {
|
const match = DRIVE_LETTER_REGEX.exec(name);
|
const driveLetter = match ? match[0] : '';
|
// A `:` is only allowed as part of a windows drive letter (ex: C:\foo)
|
// Otherwise, avoid them because they can refer to NTFS alternate data streams.
|
return (driveLetter +
|
name.substring(driveLetter.length).replace(INVALID_CHAR_REGEX, '_'));
|
}
|
/**
|
* Register an asset to be emitted as part of the bundle (if necessary)
|
* and returns the resolved public URL
|
*/
|
function fileToBuiltUrl(id, config, pluginContext, skipPublicCheck = false, canInline = false) {
|
if (!skipPublicCheck && checkPublicFile(id, config)) {
|
return config.base + id.slice(1);
|
}
|
const cache = assetCache.get(config);
|
const cached = cache.get(id);
|
if (cached) {
|
return cached;
|
}
|
const file = (0, utils_1.cleanUrl)(id);
|
const content = fs_1.default.readFileSync(file);
|
let url;
|
if (canInline && content.length < Number(config.build.assetsInlineLimit)) {
|
// base64 inlined as a string
|
url = `data:${lite_1.default.getType(file)};base64,${content.toString('base64')}`;
|
}
|
else {
|
const map = assetHashToFilenameMap.get(config);
|
const contentHash = getAssetHash(content);
|
const { search, hash } = (0, url_1.parse)(id);
|
const postfix = (search || '') + (hash || '');
|
const inputDir = (0, utils_1.normalizePath)(process.env.UNI_INPUT_DIR);
|
let fileName = file.startsWith(inputDir)
|
? path_1.default.posix.relative(inputDir, file)
|
: assetFileNamesToFileName(path_1.default.posix.join(config.build.assetsDir, '[name].[hash][extname]'), file, contentHash, content);
|
if (!map.has(contentHash)) {
|
map.set(contentHash, fileName);
|
}
|
if (!fileName.includes('/static/')) {
|
const emittedSet = emittedHashMap.get(config);
|
if (!emittedSet.has(contentHash)) {
|
pluginContext.emitFile({
|
name: fileName,
|
fileName,
|
type: 'asset',
|
source: content,
|
});
|
emittedSet.add(contentHash);
|
}
|
}
|
url = `__VITE_ASSET__${contentHash}__${postfix ? `$_${postfix}__` : ``}`;
|
}
|
cache.set(id, url);
|
return url;
|
}
|
function getAssetHash(content) {
|
return (0, crypto_1.createHash)('sha256').update(content).digest('hex').slice(0, 8);
|
}
|
exports.getAssetHash = getAssetHash;
|
function urlToBuiltUrl(url, importer, config, pluginContext) {
|
if (checkPublicFile(url, config)) {
|
return config.base + url.slice(1);
|
}
|
const file = url.startsWith('/')
|
? path_1.default.join(config.root, url)
|
: path_1.default.join(path_1.default.dirname(importer), url);
|
return fileToBuiltUrl(file, config, pluginContext,
|
// skip public check since we just did it above
|
true);
|
}
|
exports.urlToBuiltUrl = urlToBuiltUrl;
|