290 lines
12 KiB
JavaScript
290 lines
12 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.withCssInterop = withCssInterop;
|
|
const fs_1 = __importDefault(require("fs"));
|
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
const path_1 = __importDefault(require("path"));
|
|
const module_1 = require("module");
|
|
const nativewindRequire = (0, module_1.createRequire)(require.resolve("nativewind/metro"));
|
|
const connect_1 = __importDefault(nativewindRequire("connect"));
|
|
const debug_1 = nativewindRequire("debug");
|
|
const css_to_rn_1 = nativewindRequire("react-native-css-interop/dist/css-to-rn");
|
|
const expo_1 = nativewindRequire("react-native-css-interop/dist/metro/expo");
|
|
let haste;
|
|
let virtualModulesPossible = undefined;
|
|
const virtualModules = new Map();
|
|
const outputDirectory = path_1.default.resolve(__dirname, "../.cache/react-native-css-interop");
|
|
const isRadonIDE = "REACT_NATIVE_IDE_LIB_PATH" in process.env;
|
|
function withCssInterop(config, options) {
|
|
return typeof config === "function"
|
|
? async function WithCSSInterop() {
|
|
return getConfig(await config(), options);
|
|
}
|
|
: getConfig(config, options);
|
|
}
|
|
function getConfig(config, options) {
|
|
const debug = (0, debug_1.debug)(options.parent?.name || "react-native-css-interop");
|
|
debug("withCssInterop");
|
|
debug(`outputDirectory ${outputDirectory}`);
|
|
debug(`isRadonIDE: ${isRadonIDE}`);
|
|
(0, expo_1.expoColorSchemeWarning)();
|
|
const originalResolver = config.resolver?.resolveRequest;
|
|
const originalGetTransformOptions = config.transformer?.getTransformOptions;
|
|
const originalMiddleware = config.server?.enhanceMiddleware;
|
|
const poisonPillPath = "./interop-poison.pill";
|
|
fs_1.default.mkdirSync(outputDirectory, { recursive: true });
|
|
fs_1.default.writeFileSync(platformPath("ios"), "");
|
|
fs_1.default.writeFileSync(platformPath("android"), "");
|
|
fs_1.default.writeFileSync(platformPath("native"), "");
|
|
fs_1.default.writeFileSync(platformPath("macos"), "");
|
|
fs_1.default.writeFileSync(platformPath("windows"), "");
|
|
return {
|
|
...config,
|
|
transformerPath: require.resolve("react-native-css-interop/dist/metro/transformer"),
|
|
transformer: {
|
|
...config.transformer,
|
|
...{
|
|
cssInterop_transformerPath: config.transformerPath,
|
|
cssInterop_outputDirectory: path_1.default.relative(process.cwd(), outputDirectory),
|
|
},
|
|
async getTransformOptions(entryPoints, transformOptions, getDependenciesOf) {
|
|
debug(`getTransformOptions.dev ${transformOptions.dev}`);
|
|
debug(`getTransformOptions.platform ${transformOptions.platform}`);
|
|
debug(`getTransformOptions.virtualModulesPossible ${Boolean(virtualModulesPossible)}`);
|
|
const platform = transformOptions.platform || "native";
|
|
const filePath = platformPath(platform);
|
|
if (virtualModulesPossible) {
|
|
await virtualModulesPossible;
|
|
await startCSSProcessor(filePath, platform, transformOptions.dev, options, debug);
|
|
}
|
|
const writeToFileSystem = !virtualModulesPossible || !transformOptions.dev;
|
|
debug(`getTransformOptions.writeToFileSystem ${writeToFileSystem}`);
|
|
if (writeToFileSystem) {
|
|
debug(`getTransformOptions.output ${filePath}`);
|
|
const watchFn = isRadonIDE
|
|
? async (css) => {
|
|
const output = platform === "web"
|
|
? css.toString()
|
|
: getNativeJS((0, css_to_rn_1.cssToReactNativeRuntime)(css, options, debug), debug);
|
|
await promises_1.default.writeFile(filePath, output);
|
|
}
|
|
: undefined;
|
|
const css = await options.getCSSForPlatform(platform, watchFn);
|
|
const output = platform === "web"
|
|
? css.toString("utf-8")
|
|
: getNativeJS((0, css_to_rn_1.cssToReactNativeRuntime)(css, options, debug), debug);
|
|
await promises_1.default.mkdir(outputDirectory, { recursive: true });
|
|
await promises_1.default.writeFile(filePath, output);
|
|
if (platform !== "web") {
|
|
await promises_1.default.writeFile(filePath.replace(/\.js$/, ".map"), "");
|
|
}
|
|
debug(`getTransformOptions.finished`);
|
|
}
|
|
return Object.assign({}, await originalGetTransformOptions?.(entryPoints, transformOptions, getDependenciesOf));
|
|
},
|
|
},
|
|
server: {
|
|
...config.server,
|
|
enhanceMiddleware: (middleware, metroServer) => {
|
|
debug(`enhanceMiddleware.setup`);
|
|
const server = (0, connect_1.default)();
|
|
const bundler = metroServer.getBundler().getBundler();
|
|
if (options.forceWriteFileSystem) {
|
|
debug(`forceWriteFileSystem true`);
|
|
}
|
|
else {
|
|
if (!isRadonIDE) {
|
|
virtualModulesPossible = bundler
|
|
.getDependencyGraph()
|
|
.then(async (graph) => {
|
|
haste = graph?._haste;
|
|
if (graph?._fileSystem) {
|
|
ensureFileSystemPatched(graph._fileSystem);
|
|
}
|
|
ensureBundlerPatched(bundler);
|
|
});
|
|
server.use(async (_, __, next) => {
|
|
await virtualModulesPossible;
|
|
next();
|
|
});
|
|
}
|
|
}
|
|
return originalMiddleware
|
|
? server.use(originalMiddleware(middleware, metroServer))
|
|
: server.use(middleware);
|
|
},
|
|
},
|
|
resolver: {
|
|
...config.resolver,
|
|
sourceExts: [...(config?.resolver?.sourceExts || []), "css"],
|
|
resolveRequest: (context, moduleName, platform) => {
|
|
if (moduleName === poisonPillPath) {
|
|
return { type: "empty" };
|
|
}
|
|
const resolver = originalResolver ?? context.resolveRequest;
|
|
const resolved = resolver(context, moduleName, platform);
|
|
if (!("filePath" in resolved && resolved.filePath === options.input)) {
|
|
return resolved;
|
|
}
|
|
platform = platform || "native";
|
|
const filePath = platformPath(platform);
|
|
const development = context.isDev || context.dev;
|
|
const isWebProduction = !development && platform === "web";
|
|
debug(`resolveRequest.input ${resolved.filePath}`);
|
|
debug(`resolveRequest.resolvedTo: ${filePath}`);
|
|
debug(`resolveRequest.development: ${development}`);
|
|
debug(`resolveRequest.platform: ${platform}`);
|
|
if (virtualModulesPossible && !isWebProduction) {
|
|
startCSSProcessor(filePath, platform, development, options, debug);
|
|
}
|
|
return {
|
|
...resolved,
|
|
filePath,
|
|
};
|
|
},
|
|
},
|
|
};
|
|
}
|
|
async function startCSSProcessor(filePath, platform, isDev, { input, getCSSForPlatform, ...options }, debug) {
|
|
if (virtualModules.has(filePath)) {
|
|
return;
|
|
}
|
|
debug(`virtualModules ${filePath}`);
|
|
debug(`virtualModules.isDev ${isDev}`);
|
|
debug(`virtualModules.size ${virtualModules.size}`);
|
|
options = {
|
|
cache: {
|
|
keyframes: new Map(),
|
|
rules: new Map(),
|
|
rootVariables: {},
|
|
universalVariables: {},
|
|
},
|
|
...options,
|
|
};
|
|
if (!isDev) {
|
|
debug(`virtualModules.fastRefresh disabled`);
|
|
virtualModules.set(filePath, getCSSForPlatform(platform).then((css) => {
|
|
return platform === "web"
|
|
? css
|
|
: getNativeJS((0, css_to_rn_1.cssToReactNativeRuntime)(css, options), debug);
|
|
}));
|
|
}
|
|
else {
|
|
debug(`virtualModules.fastRefresh enabled`);
|
|
virtualModules.set(filePath, getCSSForPlatform(platform, (css) => {
|
|
debug(`virtualStyles.update ${platform}`);
|
|
virtualModules.set(filePath, Promise.resolve(platform === "web"
|
|
? css
|
|
: getNativeJS((0, css_to_rn_1.cssToReactNativeRuntime)(css, options), debug)));
|
|
debug(`virtualStyles.emit ${platform}`);
|
|
if (haste?.emit) {
|
|
haste.emit("change", {
|
|
eventsQueue: [
|
|
{
|
|
filePath,
|
|
metadata: {
|
|
modifiedTime: Date.now(),
|
|
size: 1,
|
|
type: "virtual",
|
|
},
|
|
type: "change",
|
|
},
|
|
],
|
|
});
|
|
}
|
|
}).then((css) => {
|
|
debug(`virtualStyles.initial ${platform}`);
|
|
return platform === "web"
|
|
? css
|
|
: getNativeJS((0, css_to_rn_1.cssToReactNativeRuntime)(css, options), debug);
|
|
}));
|
|
}
|
|
}
|
|
function ensureFileSystemPatched(fs) {
|
|
if (!fs || typeof fs.getSha1 !== "function") {
|
|
return fs;
|
|
}
|
|
if (!fs.getSha1.__css_interop_patched) {
|
|
const original_getSha1 = fs.getSha1.bind(fs);
|
|
fs.getSha1 = (filename) => {
|
|
if (virtualModules.has(filename)) {
|
|
return `${filename}-${Date.now()}`;
|
|
}
|
|
return original_getSha1(filename);
|
|
};
|
|
fs.getSha1.__css_interop_patched = true;
|
|
}
|
|
return fs;
|
|
}
|
|
function ensureBundlerPatched(bundler) {
|
|
if (bundler.transformFile.__css_interop__patched) {
|
|
return;
|
|
}
|
|
const transformFile = bundler.transformFile.bind(bundler);
|
|
bundler.transformFile = async function (filePath, transformOptions, fileBuffer) {
|
|
const virtualModule = virtualModules.get(filePath);
|
|
if (virtualModule) {
|
|
fileBuffer = Buffer.from(await virtualModule);
|
|
}
|
|
return transformFile(filePath, transformOptions, fileBuffer);
|
|
};
|
|
bundler.transformFile.__css_interop__patched = true;
|
|
}
|
|
function getNativeJS(data = {}, debug) {
|
|
debug("Start stringify");
|
|
const output = `(${stringify(data)})`;
|
|
debug(`Output size: ${Buffer.byteLength(output, "utf8")} bytes`);
|
|
return output;
|
|
}
|
|
function platformPath(platform = "native") {
|
|
return path_1.default.join(outputDirectory, `${platform}.${platform === "web" ? "css" : "js"}`);
|
|
}
|
|
function stringify(data) {
|
|
switch (typeof data) {
|
|
case "bigint":
|
|
case "symbol":
|
|
case "function":
|
|
throw new Error(`Cannot stringify ${typeof data}`);
|
|
case "string":
|
|
return `"${data}"`;
|
|
case "number":
|
|
return `${Math.round(data * 1000) / 1000}`;
|
|
case "boolean":
|
|
return `${data}`;
|
|
case "undefined":
|
|
return "null";
|
|
case "object": {
|
|
if (data === null) {
|
|
return "null";
|
|
}
|
|
else if (Array.isArray(data)) {
|
|
return `[${data
|
|
.map((value) => {
|
|
return value === null || value === undefined
|
|
? ""
|
|
: stringify(value);
|
|
})
|
|
.join(",")}]`;
|
|
}
|
|
else {
|
|
return `{${Object.entries(data)
|
|
.flatMap(([key, value]) => {
|
|
if (value === null || value === undefined) {
|
|
return [];
|
|
}
|
|
if (key.match(/[^a-zA-Z]/)) {
|
|
key = `"${key}"`;
|
|
}
|
|
value = stringify(value);
|
|
return [`${key}:${value}`];
|
|
})
|
|
.join(",")}}`;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//# sourceMappingURL=index.js.map
|