Plugin transforms static resources, vite:asset-import-meta-url can't resolve #7515
-
I'm developing a plugin that processes and renames static resources. I've got it working in Rollup, but the same plugin gets errors in Vite. I did review Vite docs on known differences, but can't seem to figure out what the difference here would be: Plugin: import { createFilter } from "@rollup/pluginutils";
import path from "path";
import fs from "fs/promises";
const DEFAULT_PLUGIN_OPTIONS = {
include: "**/*.bin",
exclude: "",
publicPath: ""
};
export default function myPlugin(pluginOptions = {}) {
pluginOptions = { ...DEFAULT_PLUGIN_OPTIONS, ...pluginOptions };
const filter = createFilter(pluginOptions.include, pluginOptions.exclude);
const assets = {}; // { [path: string]: Buffer }
return {
name: "my-plugin",
// vite-only; testing with and without these.
apply: "build",
enforce: "post",
/* Type: (options: InputOptions) => InputOptions | null */
/* Kind: sync, sequential */
options(options) {},
/* Type: (options: InputOptions) => void */
/* Kind: async, parallel */
async buildStart(options) {},
/* Type: (id: string) =>
string |
null |
{ code: string, map?: string | SourceMap, ast?: ESTree.Program, moduleSideEffects?: boolean | null } */
/* Kind: async, first */
async load(id) {
id = path.resolve(id); // Required with Vite.
if (!filter(id)) return null;
const buffer = await fs.readFile(id);
const extname = path.extname(id);
const basename = path.basename(id, extname);
const outputFileName = path.join(pluginOptions.publicPath, `${basename}.out.${extname}`);
assets[outputFileName] = buffer;
return `export default new URL("${outputFileName}", import.meta.url).href;`;
},
/* Type: (options: OutputOptions, bundle: { [fileName: string]: AssetInfo | ChunkInfo }, isWrite: boolean) => void */
/* Kind: async, sequential */
async generateBundle(options, bundle, isWrite) {
const outputDir = options.dir || path.dirname(options.file);
await Promise.all(
Object.keys(assets).map(async (outputFileName) => {
const outputPath = path.join(outputDir, outputFileName);
await fs.writeFile(outputPath, process(assets[outputFileName]));
console.log(`[my-plugin] created ${outputFileName}`);
})
).catch((e) => console.error(e));
},
};
}
function process(buffer) {
// ...
return buffer;
} Error:
Important to note here is that Vite is trying to resolve Is this an error in my plugin? Are there other ways to write a plugin that edits and renames static resources? I've seen a few issues suggesting Vite shouldn't fail when URLs don't resolve at build time (#4308, #7306, #7364), but ideally Vite would (a) check that the original path is valid and (b) not mess with the transformed path at all. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
I didn't exactly figure out what was wrong with my original code, but I did end up finding a plugin setup that works for this purpose — to load, process, and rename static assets — in both Vite and Rollup. Simplified solution below: import { createFilter, normalizePath } from "@rollup/pluginutils";
import fs from "fs/promises";
import crypto from "crypto";
import path from "path";
const PLUGIN_NAME = "bin";
const HASH_LENGTH = 8;
const DEFAULT_PLUGIN_OPTIONS = {
include: "**/*.{bin}",
exclude: "",
publicPath: "",
transforms: [],
verbose: false,
};
/**
* Import and process .bin assets.
*/
export default function bin(pluginOptions = {}) {
pluginOptions = { ...DEFAULT_PLUGIN_OPTIONS, ...pluginOptions };
const filter = createFilter(pluginOptions.include, pluginOptions.exclude);
/** Whether the plugin is running in Vite, true if configResolved() runs. */
let isVite = false;
/** Public path prepended to asset URLs. Does *not* affect the output location on disk. */
let publicPath = pluginOptions.publicPath;
/** Output location on disk. Inferred from Vite/Rollup configuration. */
let outputPath = "";
return {
name: PLUGIN_NAME,
/* Type: (options: InputOptions) => InputOptions | null */
/* Kind: sync, sequential */
options(options) {},
/* Type: (options: InputOptions) => void */
/* Kind: async, parallel */
async buildStart(options) {
// ... do some initialization ...
},
configResolved({ root, base, build: { outDir, assetsDir } }) {
isVite = true;
publicPath ||= assetsDir;
outputPath = assetsDir;
},
/* Type: (id: string) =>
string |
null |
{ code: string, map?: string | SourceMap, ast?: ESTree.Program, moduleSideEffects?: boolean | null } */
/* Kind: async, first */
async load(id) {
id = path.resolve(normalizePath(id)); // Required by Vite.
if (!filter(id)) return null;
const t0 = performance.now();
const bin = await fs.readFile(id);
const hash = generateHash(bin);
const extname = path.extname(id);
const basename = path.basename(id, extname);
const publicAssetPath = publicPath + "/" + `${basename}.${hash}.bin`;
const outputAssetPath = path.join(outputPath, `${basename}.${hash}.bin`);
this.emitFile({
type: "asset",
fileName: outputAssetPath,
source: processBin(bin),
});
const totalMS = performance.now() - t0;
// Vite logs assets automatically, Rollup doesn't.
if (!isVite) {
console.log(
""
+ green("created ")
+ greenBold(path.join("dist", outputAssetPath))
+ green(" in ")
+ greenBold(Math.round(totalMS) + "ms")
)
}
return `export default new URL("${publicAssetPath}").href;`;
},
// TODO(cleanup): Defer writing to one of these methods?
async writeBundle() {},
async generateBundle() {},
};
}
// Utilities.
function processBin(bin) {
// ... do some processing ...
return bin;
}
function generateHash(bin) {
const hash = crypto.createHash("sha1");
hash.update(bin);
return hash.digest("base64url").substring(0, HASH_LENGTH);
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return "0 Bytes";
const k = 1000;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
}
const _reset = "\x1b[0m";
const _green = "\x1b[32m";
const _greenBold = "\x1b[1;32m";
const green = (text) => `${_green}${text}${_reset}`;
const greenBold = (text) => `${_greenBold}${text}${_reset}`; |
Beta Was this translation helpful? Give feedback.
I didn't exactly figure out what was wrong with my original code, but I did end up finding a plugin setup that works for this purpose — to load, process, and rename static assets — in both Vite and Rollup. Simplified solution below: