wilsonzlin / minify-html

Extremely fast and smart HTML + JS + CSS minifier, available for Rust, Deno, Java, Node.js, Python, Ruby, and WASM
MIT License
861 stars 37 forks source link

Node package doesn't work with ESM modules #65

Closed sondr3 closed 2 years ago

sondr3 commented 2 years ago

I just noticed this problem on a project I have where I have specificed "type": "module" in the package.json. With for example @parcel/css importing and running the native binary works fine, but for @minify-html/js I get the following error:

node:internal/errors:464
    ErrorCaptureStackTrace(err);
    ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".node" for /home/sondre/Code/web/node_modules/.pnpm/@minify-html+js@0.8.0/node_modules/@minify-html/js/index.node
    at new NodeError (node:internal/errors:371:5)
    at Object.file: (node:internal/modules/esm/get_format:72:15)
    at defaultGetFormat (node:internal/modules/esm/get_format:85:38)
    at defaultLoad (node:internal/modules/esm/load:22:14)
    at ESMLoader.load (node:internal/modules/esm/loader:359:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:58)
    at new ModuleJob (node:internal/modules/esm/module_job:66:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:297:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:261:34)
    at async ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:81:21) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Node.js v17.3.0

Instead of being able to do import * as minify from "@minify-html/js" I have to do

import * as minify from "@minify-html/js"
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const mf = require("@minify-html/js") as typeof minify;

I have no idea really why this is a problem as both this and @parcel/css have .node-files in them, but this project gives me an error. The biggest difference that I can see is that this project builds the NodeJS package "manually" using node-gyp and such while @parcel/css uses napi to do the heavy lifting.

wilsonzlin commented 2 years ago

Thanks for raising. I suspect the reason is that @parcel/css uses a wrapper index.js from the looks of its "main" package.json value, whereas this library uses the index.node directly. The error occurs because Node.js doesn't support importing native modules in ESModule mode (see https://nodejs.org/api/esm.html#no-native-module-loading). I'm open to creating a wrapper index.js file to mitigate this issue.

sondr3 commented 2 years ago

It would be nice, the whole node ecosystem is ever so slowly moving towards ESM so it'd be nice to have it working without fuzzing about with imports :+1:

vhscom commented 2 years ago

The error produced by Vite is a little different. Including below for reference:

10:51:15 AM [vite] Error when evaluating SSR module //home/user/path/to/file:
Error: Failed to parse source for import analysis because the content contains invalid JS syntax. You may need to install appropriate plugins to handle the .node file format.
    at formatError (/home/user/path/to/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36769:46)
    at TransformContext.error (/home/user/path/tonode_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36765:19)
    at TransformContext.transform (/home/user/path/to/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:73659:22)
    at async Object.transform (/home/user/path/to/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36985:30)
    at async doTransform (/home/user/path/to/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:52060:29)

Solution provided by OP works. Modified to add type after first import like:

import type * as minify from "@minify-html/js"

Then including the rest verbatim:

import { createRequire } from "module";
const require = createRequire(import.meta.url);
const mf = require("@minify-html/js") as typeof minify;

SvelteKit 1.0.0-next.247 GNU/Linux 5.15.11-3

endel commented 2 years ago

When importing @minify-html/js from a child process (child_process.spawn()), and killing the main process, the child process will not terminate.

wilsonzlin commented 2 years ago

The latest version now has an index.js file that should allow for importing from ESM contexts. Let me know if it works on your end.

Note that the latest version is a minor version change, and there are changes to the Node.js library described in the changelog. Noticeably, esbuild has been replaced with minify-js, a JS minifier I wrote from scratch fully in Rust, so @endel there should no longer be any process/signals interference issues caused by the esbuild Go runtime similar to what you've described. Let me know if it works on your end.

Because of the aforementioned change, there are also now WASM versions available, if anyone is interested.

SettingDust commented 1 year ago

Seems wrong

import { minify } from '@minify-html/wasm';
         ^^^^^^
SyntaxError: Named export 'minify' not found. The requested module '@minify-html/wasm' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@minify-html/wasm';
const { minify } = pkg;
(node:3844) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

E:\javascript\article-extractor\node_modules\@minify-html\wasm\index.js:1
import * as wasm from "./index_bg.wasm";
^^^^^^

SyntaxError: Cannot use import statement outside a module

And No default export found in imported module "@minify-html/wasm"