-
-
Notifications
You must be signed in to change notification settings - Fork 888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to generate ESM-compatible standalone code #2209
Comments
FYI: This is only a problem for JSON Schema generation. If I instead |
Any news on this one? This is a big issue that actually prevents using AJV to generate ESM validation modules. |
It's not just ucs2length. I also noticed it's requiring the
const func1 = require('ajv/dist/runtime/ucs2length').default;
+ const func0 = require('ajv/dist/runtime/equal').default;
Our fix for now is to configure Vite to transform the standalone validation files so that CJS Require statements get modified to look like ES import syntax.
The same approach can be done for Rollup users. |
I solved this issue in vite using this in
As mentioned beforehand, you could also use |
The workaround with the "commonjs" plugin did not work for me, maybe because I don't compile the validation code to a file, but in-memory via the "virtual" plugin. I had to monkey-patch the generated code and replace the require() lines with proper imports: import func2 from 'ajv/dist/runtime/ucs2length'
import {fullFormats} from 'ajv-formats/dist/formats'
const formats0 = fullFormats.date Actual code may vary depending on used features. Needless to say, this is a fragile hack and no substitute for a proper fix. |
JavaScript module inconsistency strikes again. In some cases, Ajv will inject `require` calls into generated code even if you ask it to generate ESM. [This is a bug][0]. For example, here's something it adds if you use [the string `minLength` or `maxLength` properties][1]: // ... const func2 = require("ajv/dist/runtime/ucs2length").default; // ... That won't work in an ESM environment. As a workaround, I inject the following into our generated code: import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); This, along with moving `ajv` to production dependencies, should work around this issue until the bug is fixed. [0]: ajv-validator/ajv#2209 [1]: https://json-schema.org/understanding-json-schema/reference/string#length
JavaScript module inconsistency strikes again. In some cases, Ajv will inject `require` calls into generated code even if you ask it to generate ESM. [This is a bug][0]. For example, here's something it adds if you use [the string `minLength` or `maxLength` properties][1]: // ... const func2 = require("ajv/dist/runtime/ucs2length").default; // ... That won't work in an ESM environment. As a workaround, I inject the following into our generated code: import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); This, along with moving `ajv` to production dependencies, should work around this issue until the bug is fixed. [0]: ajv-validator/ajv#2209 [1]: https://json-schema.org/understanding-json-schema/reference/string#length
This is blocked by an upstream issue in AJV: ajv-validator/ajv#2209
I'm still having this issue while ESM is enabled, I see |
A workaround is compiling it in CJS format and then importing it in an ESM file like this.
Note: Absolute paths don't work with this solution, you should use relative paths. Importing the CJS like |
It's 2025 and the issue still exists with AJV To reproduce just execute: import Ajv from 'ajv'
import standaloneCode from 'ajv/dist/standalone'
const ajv = new Ajv({code: {source: true, esm: true},})
console.log(standaloneCode(ajv, {validateJsonSchemaV7: 'http://json-schema.org/draft-07/schema#'})) And then unfortunately you can see this in the produced code: const func0 = require("ajv/dist/runtime/equal").default; That causes this runtime error:
|
The other issue is, isn't the produced code standalone? Then what is |
As is, no it isn't if your schema has rules which requires (pun intended) the |
We have an awfully kludgy fix where we replace I'd gladfully assist on a PR, implementing a proper solution, if needed. |
I had the misfortune of running into this problem as well. I tried with the various vite/rollup common-js plugins but to no avail, and I think it's because const formats96 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}["date-time"]; To workaround this, I (also) had to do a bunch of regex'ing. I've pasted the crux of it here in the hope that someone else does not waste as much time as I have on this. // assume `moduleCode` is generated from `standaloneCode(ajv, {...})`
const preamble = [
`// @ts-nocheck`,
`"use strict";`,
`import { fullFormats } from "ajv-formats/dist/formats";`,
].join("\n");
const imports = new Set<string>();
const formatsRegex = /const (formats\d+)\s*=\s\{.+\}(.+);/g;
const requireRegex = /const (\S+)\s*=\s*require\((.+)\)\.(\S+);/g;
const replaced = moduleCode
.replaceAll(
formatsRegex,
(_match, p1, p2) => `const ${p1} = fullFormats${p2}`
)
.replace(requireRegex, (_match, p1, p2, p3) => {
imports.add(`import { ${p3} as ${p1} } from ${p2};`);
return "";
})
// since `use strict` should be the first non-comment line, and we're adding
// more lines in the preamble, we have moved it into the preamble.
.replace(`"use strict";\n`, "");
const uglyOut = [preamble, Array.from(imports).join("\n"), "", replaced].join(
"\n"
);
process.stdout.write(
// prettify the generated code (not that it really matters).
await prettier.format(uglyOut, { parser: "babel" }),
"utf-8"
); The code above also formats the output with prettier, which is of course not necessary. |
I tackled two different scenarios using separate approaches:
|
The version of Ajv you are using
8.12
The environment you have the problem with
node v16.16.0, ESM project (
{type: module}
)Your code (please make it as small as possible to reproduce the issue)
Code to compile AJV schema:
Results in node.js v8+
Able to successfully compile standalone code; unable to import in ESM project
Results and error messages in your platform
I am using the standalone validation code functionality to generate compiled schema files at build time. I am compiling the code with the AJV library in a JS script and specifying
esm: true
to compile the standalone code for ESM. The compilation works and I am writing the compiled schema to a JS file, but I am unable to import the standalone code from this schema file in my ESM project because it imports theucs2length
utility via arequire
statement (const func2 = require("ajv/dist/runtime/ucs2length").default
).Here is an example schema compiled via standalone for ESM support (generated with the above script:
I'm able to import and use the schema file by manually replacing the
require
with animport
statement. Am I overlooking something to generate standalone validation code that is fully ESM-compatible?The text was updated successfully, but these errors were encountered: