UNPKG

@linaria/vite

Version:

Blazing fast zero-runtime CSS in JS library

149 lines 5 kB
// src/index.ts import { existsSync } from "fs"; import path from "path"; import { createFilter } from "@rollup/pluginutils"; import { optimizeDeps } from "vite"; import { transform, slugify, TransformCacheCollection } from "@linaria/babel-preset"; import { linariaLogger } from "@linaria/logger"; import { createFileReporter, getFileIdx, syncResolve } from "@linaria/utils"; function linaria({ debug, include, exclude, sourceMap, preprocessor, ...rest } = {}) { const filter = createFilter(include, exclude); const cssLookup = {}; const cssFileLookup = {}; let config; let devServer; const { emitter, onDone } = createFileReporter(debug ?? false); const targets = []; const cache = new TransformCacheCollection(); return { name: "linaria", enforce: "post", buildEnd() { onDone(process.cwd()); }, configResolved(resolvedConfig) { config = resolvedConfig; }, configureServer(_server) { devServer = _server; }, load(url) { const [id] = url.split("?", 1); return cssLookup[id]; }, /* eslint-disable-next-line consistent-return */ resolveId(importeeUrl) { const [id] = importeeUrl.split("?", 1); if (cssLookup[id]) return id; return cssFileLookup[id]; }, handleHotUpdate(ctx) { if (ctx.modules.length) return ctx.modules; const affected = targets.filter( (x) => ( // file is dependency of any target x.dependencies.some((dep) => dep === ctx.file) || // or changed module is a dependency of any target x.dependencies.some((dep) => ctx.modules.some((m) => m.file === dep)) ) ); const deps = affected.flatMap((target) => target.dependencies); for (const depId of deps) { cache.invalidateForFile(depId); } return affected.map((target) => devServer.moduleGraph.getModuleById(target.id)).concat(ctx.modules).filter((m) => !!m); }, async transform(code, url) { const [id] = url.split("?", 1); if (url.includes("node_modules") || !filter(url) || id in cssLookup) return; const log = linariaLogger.extend("vite"); log("Vite transform", getFileIdx(id)); const asyncResolve = async (what, importer, stack) => { const resolved = await this.resolve(what, importer); if (resolved) { if (resolved.external) { const resolvedId2 = syncResolve(what, importer, stack); log("resolve \u2705 '%s'@'%s -> %O\n%s", what, importer, resolved); return resolvedId2; } log("resolve \u2705 '%s'@'%s -> %O\n%s", what, importer, resolved); const resolvedId = resolved.id.split("?", 1)[0]; if (resolvedId.startsWith("\0")) { return null; } if (!existsSync(resolvedId)) { await optimizeDeps(config); } return resolvedId; } log("resolve \u274C '%s'@'%s", what, importer); throw new Error(`Could not resolve ${what}`); }; const transformServices = { options: { filename: id, root: process.cwd(), preprocessor, pluginOptions: rest }, cache, eventEmitter: emitter }; const result = await transform(transformServices, code, asyncResolve); let { cssText, dependencies } = result; if (!cssText) return; dependencies ??= []; const slug = slugify(cssText); const cssFilename = path.normalize(`${id.replace(/\.[jt]sx?$/, "")}_${slug}.css`).replace(/\\/g, path.posix.sep); const cssRelativePath = path.relative(config.root, cssFilename).replace(/\\/g, path.posix.sep); const cssId = `/${cssRelativePath}`; if (sourceMap && result.cssSourceMapText) { const map = Buffer.from(result.cssSourceMapText).toString("base64"); cssText += `/*# sourceMappingURL=data:application/json;base64,${map}*/`; } cssLookup[cssFilename] = cssText; cssFileLookup[cssId] = cssFilename; result.code += ` import ${JSON.stringify(cssFilename)}; `; if (devServer?.moduleGraph) { const module = devServer.moduleGraph.getModuleById(cssId); if (module) { devServer.moduleGraph.invalidateModule(module); module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now(); } } for (let i = 0, end = dependencies.length; i < end; i++) { const depModule = await this.resolve(dependencies[i], url, { isEntry: false }); if (depModule) dependencies[i] = depModule.id; } const target = targets.find((t) => t.id === id); if (!target) targets.push({ id, dependencies }); else target.dependencies = dependencies; return { code: result.code, map: result.sourceMap }; } }; } export { linaria as default }; //# sourceMappingURL=index.mjs.map