html-express-js
html-express-js copied to clipboard
Use with express - which is ES5
I'm trying to figure out if this is usable during this weird interim time when ES5 and ES6 have to co-exist.
I may have made some mistaken assumptions in my explanation below...
html-express-js seems to require ES6 - i.e. "import" - this is also what its docs show, and require('html-express-js') doesn't work
express seems to be ES5 - all its documentation shows 'require', even if express will work as a module many other things around it that I'm using won't (yet), so my "Main.js" is ES5 and uses require.
This doesn't need to be a problem - as could probably use what I believe are called "ES5 dynamic imports"
const htmlExpress = import('html-express-js')
except html-express-js exports both default and named functions, and I don't think its possible to see them via dynamic imports.
Maybe this is obvious to others, but I can't figure out the trick to get this to work in ES5 so maybe an addition to the README.md would be useful if I'm missing something.
Hey @mitra42, I'm having a little trouble understanding what the issue is, which may be specific to your project. Is it possible for you to give me an example set of code so that I can reproduce what you're seeing?
I get the following errror
import htmlExpress, { staticIndexHandler } from 'html-express-js'; // Note this is a module
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:360:18)
at wrapSafe (node:internal/modules/cjs/loader:1088:15)
at Module._compile (node:internal/modules/cjs/loader:1123:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Module.load (node:internal/modules/cjs/loader:1037:32)
at Module._load (node:internal/modules/cjs/loader:878:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47
Node.js v18.12.1
That import line appears in my Main.js, which is run as
node Main.js
So Main.js isn't a module and therefore cannot use import it has to use require
In particular it loads express via
const express = require('express');
@markcellus also stuck in a dilemma here, I am working on a project that uses CommonJS modules, the one that exports things like:
const myFeature = function() {
return 'sample';
};
module.exports = {
myFeature: myFeature,
}
In this type of project the only way to import things is through require keyword, an example would be:
const express = require('express');
When using html-express-js however, importing via require is not possible because the html-express-js is only exposing functionality through ES6 export syntax. An example of this is the one in src/index.js in this repo:
https://github.com/markcellus/html-express-js/blob/015f3cc42479966ccd96f1dfad167cc3af133070/src/index.js#L103-L123
Also in package.json type explicitly set to type: module.
Currently for us to use html-express-js in our project is to convert our project to use modules which will require us to re-write the entire codebase to support ES6 import syntax which I did in my previous projects but not everyone are willing to dedicate such time and energy in order to use a library.
Most library often support both CommonJS and ES6 import syntax, one such library is short-unique-id. This particular library uses esbuild to build for both CommonJS and ES6 as seen in their build script. We can support both CommonJS and ES6 using the same technique. Not sure if I will have time to make PR, once I have finished the thing I'm working on maybe I could help. Ping me if you would like help regarding this.
TL;DR
CommonJS projects cannot use html-express-js because html-express-js strictly builds using ES6 modules:
- ❌ Cannot do
const htmlExpress = require('html-express-js');becausehtml-express-jsdoes not support CommonJS exports - ❌ Cannot do
import htmlExpress, { staticIndexHandler } from 'html-express-js';because our projects cannot use ES6importsyntax
Workaround using dynamic import
@mitra42 hi, we can use the following workaround at the moment while CommonJS modules are not yet supported. This is how I use html-express-js in our codebase:
// index.js
require('dotenv').config();
const { resolve } = require('node:path');
const express = require('express');
const app = express();
const serverless = require('serverless-http');
const cors = require('cors');
(async () => {
app.use(express.urlencoded({ extended: true }));
app.use(express.json({ type: 'application/json', limit: '400mb' }));
app.use(express.static('public'));
// use dynamic import to import html-express-js
const htmlExpressPkg = await import('html-express-js');
// desctructure the imported package, we assign htmlExpress alias to default
const { default: htmlExpress, staticIndexHandler } = htmlExpressPkg;
/**
* Configure html-express-js as the rendering engine.
* Templates will be in the local directory ./public
*/
app.engine('js', htmlExpress());
app.set('view engine', 'js');
app.set('views', `${__dirname}/public`);
app.get('/', (_, res) => {
res.send('Hello world');
});
const listener = app.listen(process.env.PORT, function() {
console.log(`App is listening on port ${listener.address().port}`);
});
})();
module.exports.handler = serverless(app);
The code above uses dynamic import and destructures the imported package to properly assign name to default export. This requires to wrap our code inside an Immediately invoked async function expression so we can use await keyword on import statement. Similar example is showcased on the documentation about dynamic import on MDN. I have not encountered any issues with this setup at the moment.
Update
Creating a view is impossible using this approach, the underlying issue is that first the usage is tightly coupled with ES6 syntax and second we cannot use modules.exports due to the first issue mentioned:
// public/homepage.js
import { html } from 'html-express-js';
export const view = (data, state) => html`
<!DOCTYPE html>
<html lang="en">
<head>
${state.includes.head}
<title>${data.title}</title>
</head>
<body>
<h1>This is the homepage for ${data.name}</h1>
</body>
</html>
`;