Skip to content

Commit

Permalink
Getting the no-modules TypeScript *.d.ts Files Working (#2396)
Browse files Browse the repository at this point in the history
* In NoModule builds, switched "export" keyword to "declare" in d.ts file.

This aims to be the first step at getting the d.ts file working. The reason for this is that the TypeScript (3.8.3)
compiler ignores "declare" statements if it sees "export" statements. Not sure if that's a bug in TypeScript.

Either way, all I really did here was scan through all changes to `self.typescript` and see if it could add an "export".
The only big wild-card I found was the `typescript_custom_sections`, which I think exists just to let `wasm_buildgen`
annotations to add extra typescript to the document?

* Trying to putting the generated methods into a `wasm_bindgen` namespace.

This is a bit crude, basically anything before the "init" block is put in this namespace.
Hopefully this works in general. I'm not 100% sure yet.

* Fixed a typo in the comments.

* In NoModules d.ts files `init()` is renamed to `wasm_bindgen()`.

Based on the output JavaScript this seems to be how it works.

* Realized that the function declarations couldn't also have `declare`s.

Then traced through the other instances where I'd switched `export` to `declare` and switched them over if they were going to end up in the same `wasm_bindgen` namespace.

* Realized there was a nice no_modules() method.

* Removing the extra spaces at the end of the .d.ts files.

* Realized that can leave the `export` in the namespace declaration.

* Adding tests for the no-modules target.

I'm hoping that `run.sh` is what the CI runs.

* Tried to get the no-modules TypeScript tests to build against actual TypeScript.

So now the `*.d.ts` files will actually be build against (modified) `*.ts` files. This should be a better check than only verifying TypeScript doesn't fail when given just the `*.d.ts` files (what it did before).

Note that the `*.ts` files are generated from the `*.ts` files in `src` using some fairly simple Regular Expressions.

This skips checking the `typescript_tests_bg.wasm.d.ts` file, as I have no experience using that.

* Adding more info about the testing changes in run.sh.
  • Loading branch information
aaron-human authored Feb 8, 2021
1 parent 03c692e commit 5442f26
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 6 deletions.
35 changes: 29 additions & 6 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ impl<'a> Context<'a> {
module_name: &str,
needs_manual_start: bool,
) -> Result<(String, String, Option<String>), Error> {
let mut ts = self.typescript.clone();
let mut ts;
let mut js = String::new();
let mut start = None;

Expand Down Expand Up @@ -441,6 +441,16 @@ impl<'a> Context<'a> {
}
}

// Before putting the static init code declaration info, put all existing typescript into a `wasm_bindgen` namespace declaration.
// Not sure if this should happen in all cases, so just adding it to NoModules for now...
if self.config.mode.no_modules() {
ts = String::from("declare namespace wasm_bindgen {\n\t");
ts.push_str(&self.typescript.replace("\n", "\n\t"));
ts.push_str("\n}\n");
} else {
ts = self.typescript.clone();
}

let (init_js, init_ts) = init;

ts.push_str(&init_ts);
Expand Down Expand Up @@ -556,11 +566,23 @@ impl<'a> Context<'a> {
("", "")
};
let arg_optional = if has_module_or_path_optional { "?" } else { "" };
// With TypeScript 3.8.3, I'm seeing that any "export"s at the root level cause TypeScript to ignore all "declare" statements.
// So using "declare" everywhere for at least the NoModules option.
// Also in (at least) the NoModules, the `init()` method is renamed to `wasm_bindgen()`.
let setup_function_declaration;
let declare_or_export;
if self.config.mode.no_modules() {
declare_or_export = "declare";
setup_function_declaration = "declare function wasm_bindgen";
} else {
declare_or_export = "export";
setup_function_declaration = "export default function init";
}
Ok(format!(
"\n\
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;\n\
{declare_or_export} type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;\n\
\n\
export interface InitOutput {{\n\
{declare_or_export} interface InitOutput {{\n\
{output}}}\n\
\n\
/**\n\
Expand All @@ -572,11 +594,12 @@ impl<'a> Context<'a> {
*\n\
* @returns {{Promise<InitOutput>}}\n\
*/\n\
export default function init \
(module_or_path{}: InitInput | Promise<InitInput>{}): Promise<InitOutput>;
",
{setup_function_declaration} \
(module_or_path{}: InitInput | Promise<InitInput>{}): Promise<InitOutput>;\n",
memory_doc, arg_optional, memory_param,
output = output,
declare_or_export = declare_or_export,
setup_function_declaration = setup_function_declaration,
))
}

Expand Down
2 changes: 2 additions & 0 deletions crates/typescript-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pkg
dist
src_no_modules
dist_no_modules
12 changes: 12 additions & 0 deletions crates/typescript-tests/no_modules.tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "es6",
"noImplicitAny": true,
"sourceMap": true,
"outDir": "dist_no_modules",
},
"include": [
"pkg/no_modules/*.d.ts",
"src_no_modules/*.ts",
]
}
34 changes: 34 additions & 0 deletions crates/typescript-tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,37 @@ if [ ! -d node_modules ]; then
fi

npm run tsc

# Build using no-modules.
mkdir pkg/no_modules
cargo run -p wasm-bindgen-cli --bin wasm-bindgen -- \
../../target/wasm32-unknown-unknown/debug/typescript_tests.wasm \
--out-dir pkg/no_modules \
--target no-modules \
--typescript

# Then create copies of the TypeScript tests used on "--target web" (i.e. those in ./src) but adjust them to work with "--target no-modules".
# Store the new generated test files under "src_no_modules".
rm -rf src_no_modules
mkdir src_no_modules
cd src
for filename in *.ts; do
if grep -q "_bg.wasm" "$filename"
then
# I am unsure how to import or test the "*_bg.wasm" file.
# So any test file that includes those is currently being skipped.
echo "Ignoring $filename as it uses the *.wasm.d.ts file."
else
path="../src_no_modules/$filename"
# Copy over every line EXCEPT for the import statements (since "no-modules" has no modules to import).
grep -v -w "import" "$filename" > "$path"
# Then replace all of the instances of "wbg" (the namespace all the tests use to import the *.d.ts files from "--target web") with "wasm_bindgen" (the namespace the `no-modules` *.d.ts files use).
sed -i "s/wbg\./wasm_bindgen./g" "$path"
sed -i "s/wbg /wasm_bindgen /g" "$path"
sed -i "s/wbg\[/wasm_bindgen[/g" "$path"
fi
done
cd ..

# Then try to build the typescript in the src_no_modules folder against the pkg/no_modules build.
npm run tsc -- -p no_modules.tsconfig.json

0 comments on commit 5442f26

Please sign in to comment.