Skip to content

Commit 4a4105f

Browse files
authored
[js] Module import support (#12384)
* [js] Module import support * Generate aliases * Allow `@:js.import(define)` * add package.json * move test
1 parent 9583f7c commit 4a4105f

12 files changed

Lines changed: 268 additions & 0 deletions

File tree

src-json/meta.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,13 @@
561561
"targets": ["TClass"],
562562
"links": ["https://haxe.org/manual/target-javascript-require.html"]
563563
},
564+
{
565+
"name": "JsImport",
566+
"metadata": ":js.import",
567+
"doc": "Generate ES module import statement for given extern. Produces import lines at the top of the generated JS output.",
568+
"platforms": ["js"],
569+
"targets": ["TClass"]
570+
},
564571
{
565572
"name": "LuaRequire",
566573
"metadata": ":luaRequire",

src/generators/genjs.ml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,71 @@ let generate js_gen com =
16661666

16671667
let ctx = alloc_ctx com es_version in
16681668
Gctx.map_source_header com.defines (fun s -> print ctx "// %s\n" s);
1669+
1670+
let import_statements = ref [] in
1671+
List.iter (fun mt -> match mt with
1672+
| TClassDecl c when (has_class_flag c CExtern) && Meta.has Meta.JsImport c.cl_meta && is_directly_used ctx.com c.cl_meta ->
1673+
let _, args, mp = Meta.get Meta.JsImport c.cl_meta in
1674+
let id = snd c.cl_path in
1675+
let flat_path = Path.flat_path (get_generated_class_path c) in
1676+
let alias = try
1677+
fst (Native.get_native_name c.cl_meta)
1678+
with Not_found ->
1679+
c.cl_meta <- (Meta.Native,[EConst (String(flat_path,SDoubleQuotes)),null_pos],null_pos) :: c.cl_meta;
1680+
Native.apply_native_paths mt;
1681+
flat_path
1682+
in
1683+
let err () =
1684+
abort ("Unsupported @:js.import format. Use:\n" ^
1685+
" @:js.import('mylib.js')\n" ^
1686+
" @:js.import('mylib.js', 'name')\n" ^
1687+
" @:js.import(@default 'mylib.js')\n" ^
1688+
" @:js.import(@star 'mylib.js')\n" ^
1689+
"'mylib.js' can also be replaced with mylibjs_path custom define,\nif you set it as -D mylibjs_path=\"mylib.js\"")
1690+
mp
1691+
in
1692+
let get_module_name expr =
1693+
match expr with
1694+
| EConst(String(module_name,_)),_ -> module_name
1695+
| EConst(Ident(define)),_ ->
1696+
begin try
1697+
let s = Define.raw_defined_value com.defines define in
1698+
Helper.unquote s
1699+
with Not_found ->
1700+
abort ("Define " ^ define ^ " with js library path is not specified") mp;
1701+
end
1702+
| _ -> err()
1703+
in
1704+
(match args with
1705+
(* @:js.import(@star "module") - namespace import *)
1706+
| [EMeta ((Meta.Custom "star",[],_),ename),_] ->
1707+
let module_name = get_module_name ename in
1708+
import_statements := (Printf.sprintf "import * as %s from \"%s\";" alias module_name) :: !import_statements
1709+
(* @:js.import(@default "module") - default import *)
1710+
| [EMeta ((Meta.Custom "default",[],_),ename),_] ->
1711+
let module_name = get_module_name ename in
1712+
import_statements := (Printf.sprintf "import %s from \"%s\";" alias module_name) :: !import_statements
1713+
(* @:js.import("module") - named import using class name *)
1714+
| [ename] ->
1715+
let module_name = get_module_name ename in
1716+
import_statements := (Printf.sprintf "import { %s as %s } from \"%s\";" id alias module_name) :: !import_statements
1717+
(* @:js.import("module", "exportName") - named import with alias *)
1718+
| [ename; (EConst(String(export_name,_)),_)] ->
1719+
let module_name = get_module_name ename in
1720+
import_statements := (Printf.sprintf "import { %s as %s } from \"%s\";" export_name alias module_name) :: !import_statements
1721+
| exprs ->
1722+
err ()
1723+
)
1724+
| _ -> ()
1725+
) com.types;
1726+
(match !import_statements with
1727+
| [] -> ()
1728+
| lines ->
1729+
List.iter (fun line ->
1730+
print ctx "%s\n" line
1731+
) (List.rev lines)
1732+
);
1733+
16691734
if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
16701735
if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
16711736

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--main Main
2+
-dce full
3+
-D analyzer-optimize
4+
--class-path src
5+
--js bin/main.js
6+
--cmd node bin/main
7+
-D pixijs_path="../pixi.js"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
--main Main
2+
-dce full
3+
-D analyzer-optimize
4+
--class-path src
5+
--js bin/main.js
6+
--cmd node bin/main
7+
-D js-es=6
8+
-D pixijs_path="../pixi.js"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const str = "str";
2+
export function increment(x) {
3+
return x + 1;
4+
}
5+
6+
export default function def() {
7+
return "default function";
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default class Lib {
2+
static def() {
3+
return "default static";
4+
}
5+
}
6+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function def() {
2+
return "default function";
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export class Foo {
2+
static name() {
3+
return "foo";
4+
}
5+
}
6+
7+
export class Bar {
8+
static name() {
9+
return "bar";
10+
}
11+
}
12+
13+
export default class DefClass {
14+
name() {
15+
return "default class";
16+
}
17+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export class Application {
2+
constructor(options) {}
3+
test() {
4+
return "test";
5+
}
6+
static name() {
7+
return "Application";
8+
}
9+
}
10+
11+
export class Assets {
12+
static load(url) {
13+
return url;
14+
}
15+
}
16+
17+
export default class {
18+
static name() {
19+
return "default name";
20+
}
21+
};

0 commit comments

Comments
 (0)