Comments (8)
I'm not sure how eval can mimic sentences like import { hello } from './hello.js´
. Worth a try. Getting the hello
variable might be tricky.
from nue.
Can't we use eval
function (although it may not be secure) or it's alternatives?
from nue.
I don't think you can import modules with eval.
from nue.
ie. I'm open to any option that works. Let's tinker with the possible security issues / other concerns later.
from nue.
In the example you've shared, we have
...
const text = await (await fetch(url)).text();
const dataURL = `data:text/javascript;base64,${btoa(text)}`;
const { Buffer } = await import(dataURL);
...
Can't we replace it with
...
const text = await (await fetch(url)).text();
eval(test);
...
from nue.
Why would it be tricky? Wouldn't eval parse it normally?
from nue.
@tipiirai
Did you work this out?
I came up with a fairly simple, but very primitive solution to transpile the source by hand. We could look up all import statements and transform them to dynamic imports, which are allowed in non-module environments, like eval
and Function
.
Here is my sample implementation. It uses a regex for the pattern lookup, so it's very error-prone. It works, but I'm not convinced anyone should use this:
const BunTranspiler = new Bun.Transpiler({
loader: 'js',
// minifyWhitespace: true, // TEMP: Commented out for debugging reasons
})
function transpileImports(source) {
const imports = BunTranspiler
.scanImports(source)
.filter(imp => imp.kind == 'import-statement')
.map(imp => imp.path)
// Slightly modified version of a regex made by Antón Kryukov Chinaev @antonkc
// https://github.com/antonkc/MOR/blob/main/matchJsImports.md
const regex = /(?<=(?:[\s\n;])|^)(?:import[\s\n]*)((?:(?:[_\$\w][_\$\w0-9]*)(?:[\s\n]+(?:as[\s\n]+(?:[_\$\w][_\$\w0-9]*)))?(?=(?:[\n\s]*,[\n\s]*[\{\*])|(?:[\n\s]+from)))?)[\s\n,]*((?:\*[\n\s]*(?:as[\s\n]+(?:[_\$\w][_\$\w0-9]*))(?=[\n\s]+from))?)[\s\n,]*((?:\{[n\s]*(?:(?:[_\$\w][_\$\w0-9]*)(?:[\s\n]+(?:as[\s\n]+(?:[_\$\w][_\$\w0-9]*)))?[\s\n]*,?[\s\n]*)*\}(?=[\n\s]*from))?)(?:[\s\n]*((?:from)?))[\s\n]*(?:["']([^"']*)(["']))[\s\n]*?;?/gm
return BunTranspiler
.transformSync(source) // Strips comments, minifies whitespaces, etc.
.replaceAll(regex, (input, defaultImport, wildcardImport, namedImports, from, moduleName, quote) => {
// Just to be more confident, that the import statement is indeed an import statement,
// though it's incorrect in some rare cases, but more on that later on
if (!imports.includes(moduleName)) return input
// TODO: Resolve the path to run the script in the right context
const path = quote + moduleName + quote
if (wildcardImport)
if (defaultImport)
return `const ${wildcardImport.split(' ').at(-1)} = await import(${path}), ${defaultImport} = ${wildcardImport.split(' ').at(-1)}.default;`
else return `const ${wildcardImport.split(' ').at(-1)} = await import(${path});`
else if (namedImports)
if (defaultImport)
return `const ${namedImports.replaceAll(' as ', ': ').slice(0, -1)}, default: ${defaultImport} } = await import(${path});`
else return `const ${namedImports.replaceAll(' as ', ': ')} = await import(${path});`
else if (defaultImport) return `const { default: ${defaultImport} } = await import(${path});`
return `await import (${path});`
})
}
Given the source:
import defaultImport1 from "./module";
import * as wildcardImport1 from "./module";
import { namedImport1 } from "./module";
import { namedImport1 as alias1 } from "./module";
import { default as alias2 } from "./module";
import { namedImport2, namedImport3 } from "./module";
import defaultImport2, * as wildcardImport2 from "./module";
import { namedImport4, namedImport1 as alias3, /* ... */ } from "./module";
import defaultImport3, { namedImport5, /* ... */ } from "./module";
import "./module";
It transpiles to:
const { default: defaultImport1 } = await import("./module");
const wildcardImport1 = await import("./module");
const {namedImport1} = await import("./module");
const {namedImport1: alias1} = await import("./module");
const {default: alias2} = await import("./module");
const {namedImport2, namedImport3} = await import("./module");
const wildcardImport2 = await import("./module"), defaultImport2 = wildcardImport2.default;
const {namedImport4, namedImport1: alias3} = await import("./module");
const {namedImport5, default: defaultImport3 } = await import("./module");
await import ("./module");
And in action:
// module.js
export default 42
export const namedImport1 = 42
export const namedImport2 = 42
export const namedImport3 = 42
export const namedImport4 = 42
export const namedImport5 = 42
const source = `
import defaultImport1 from "./module";
import * as wildcardImport1 from "./module";
import { namedImport1 } from "./module";
import { namedImport1 as alias1 } from "./module";
import { default as alias2 } from "./module";
import { namedImport2, namedImport3 } from "./module";
import defaultImport2, * as wildcardImport2 from "./module";
import { namedImport4, namedImport1 as alias3, /* ... */ } from "./module";
import defaultImport3, { namedImport5, /* ... */ } from "./module";
import "./module";
console.log({
alias1,
alias2,
alias3,
namedImport1,
namedImport2,
namedImport3,
namedImport4,
namedImport5,
defaultImport1,
defaultImport2,
defaultImport3,
wildcardImport1,
wildcardImport2,
})
`
const transpiled = transpileImports(source)
const AsyncFunction = async function () {}.constructor
AsyncFunction(transpiled)() /* =>
{
alias1: 42,
alias2: 42,
alias3: 42,
namedImport1: 42,
namedImport2: 42,
namedImport3: 42,
namedImport4: 42,
namedImport5: 42,
defaultImport1: 42,
defaultImport2: 42,
defaultImport3: 42,
wildcardImport1: Module {
default: 42,
namedImport1: 42,
namedImport2: 42,
namedImport3: 42,
namedImport4: 42,
namedImport5: 42,
},
wildcardImport2: Module {
default: 42,
namedImport1: 42,
namedImport2: 42,
namedImport3: 42,
namedImport4: 42,
namedImport5: 42,
},
}
*/
Issues that I've already found:
-
Regex doesn't match type imports
-
Regex doesn't match string literal named imports:
import { "string literal" as alias } from "module"
-
Regex matches all import statement syntax instances despite its context, for example in strings. We verify that with Bun's
scanImports()
, but if the source code contains both a real import statement, and a fake one, they both get transpiled:"import 'module'"; import 'module';
Transpiles to:
"await import ('module')"; await import ('module');
from nue.
This is a highly desirable feature, and I'm looking forward to it. I think there are 3-level component life time:
- compile-time
- server side at runtime
- client side at runtime
from nue.
Related Issues (20)
- create error
- Update CLI help message to represent current options HOT 1
- Custom JSX/TSX components HOT 2
- Syntax error HOT 1
- Pending when creating projects with bun under Windows HOT 12
- The path of the route is expected to support regular expressions HOT 1
- component at layout.html compile error HOT 3
- When '{}' or',' in html , How to escape? HOT 1
- It can not start the server with nuekit 0.5.3, but works with nue 0.4.3 HOT 6
- auto generate manifest.json file
- a bug in the nuecli root HOT 5
- unmounted() Why is it not executed?
- Reactive values are not updated? why? HOT 3
- Page router doesn't mount components. Refresh needed to properly mount. HOT 2
- "draw_sections: true" results in nested sections HOT 5
- When iterating collections: can we render the markdown content of an item? HOT 5
- three-tiered directory structure layout HOT 1
- Add default`text` property to default `data` object available to page layouts.
- SPA demo not working when deploy on subpath of domain
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nue.