To repro:
rm -rf denotest
mkdir denotest
cd denotest
git clone https://github.com/bikeshaving/crank.git
cd crank
npm i
npm run prebuild
npm run build
cd ..
cat <<EOF > test.ts
import {createElement} from './crank/src/index.ts';
import {renderer} from './crank/src/html.ts';
console.log(renderer.render(createElement('h1', {id: 'foo'}, 'Hello World'))
EOF
deno run test.ts
Actual:
Compile file:///private/tmp/denotest/test.ts
error: Uncaught NotFound: Cannot resolve module "file:///private/tmp/denotest/crank/src/events" from "file:///private/tmp/denotest/crank/src/index.ts"
FWIW, this _does_ work in deno:
import {createElement} from 'https://unpkg.com/@bikeshaving/[email protected]/esm/index.js'
import {renderer} from 'https://unpkg.com/@bikeshaving/[email protected]/esm/html.js';
console.log(renderer.render(createElement('h1', {id: 'foo'}, 'Hello world')));
… but I believe it's not consuming the types (or even the sourcemaps) that way.
https://github.com/denoland/deno/issues/5308
You're going to love this: the best practice I can find is to write TSC-compatible TS (import './index')and transpile it to deno-compatible TS (import './index.ts').
Leadership!!!
Yeah, I think the path forward is to do like above and use something like unpkg and import the esm js artifacts. (Note that you should be importing the files in the root for maximum compatibility in 0.2.0. In case you’re interested, I’m the author of the following issue asking for guidance (https://github.com/denoland/deno/issues/3196) but there doesn’t seem to be much movement on that front. The problem is that typescript forces you to not specify file extensions, while deno forces you to, and it seems like they’re at an impasse about this. I personally would prefer to have explicit file extensions and never understood the TS team’s rationale behind not allowing it, but whatever.
Something like this should work:
/// <reference types="https://unpkg.com/@bikeshaving/[email protected]/index.d.ts" />
import {createElement} from 'https://unpkg.com/@bikeshaving/[email protected]/index.js'
/// <reference types="https://unpkg.com/@bikeshaving/[email protected]/html.d.ts" />
import {renderer} from 'https://unpkg.com/@bikeshaving/[email protected]/html.js';
I’m not sure if they changed the API for the 1.0 release though. Searching the deno docs/github for “triple slash directive” should give you the latest information.
Thanks for looking into this stuff! Very curious about your thoughts on deno. I also think that the greenfield landscape of deno offers a huge opportunity in terms of evangelism, like if we can convince the deno community that Crank, and specifically its focus on async/generator functions is a perfect match for Deno’s API, which uses async iterators everywhere, we could jumpstart adoption.
This page seems to have more information. It looks like triple slash references are what we are supposed to do on our end as library authors, while the deno-types comments are what library consumers do.
I'm feeling pretty "meh" on deno 1.0.
deps.ts will make it harder to do static analysis. (How do you automatically flag known security issues when dependencies are just URLs?) Import maps are a better solution, but they're "unstable" in deno 1.0, and they still don't address the static analysis problem.Also, I predict that the browser people will cook up their own SRI metadata file, based around import maps, and then we'll have wanted Deno to use that, instead.
haha this is nightmare fuel.
I agree with all these points, but top-level await and a modern standard lib is kinda tempting.
Funny you should mention it. Top-level await doesn't work in deno's REPL. https://github.com/denoland/deno/issues/3700
TLA's just not ready yet. The V8 team is actively working on it. https://bugs.chromium.org/p/v8/issues/detail?id=9344
When they ship it, Node will use it, too. https://github.com/nodejs/node/issues/31410
TLA is yet another area where deno's reach exceeded its grasp. What I feel like we learned from Node is that CLI JS has to stay one step behind the browsers. It's frustrating, because the browsers move so slowly, but getting out on the bleeding edge is just asking for incompatibility later down the road.
IMO, the _only_ safe way to get ahead of the browsers is transpilation. Everything else has to wait.
As for modernizing the stdlib, I expect we'll see Node modernize its stdlib over time, e.g. fs/promises. https://nodejs.org/api/fs.html#fs_fs_promises_api
The following almost works.
server.tsx
/** @jsx createElement */
// @deno-types="https://unpkg.com/@bikeshaving/[email protected]/index.d.ts"
import {createElement} from "https://unpkg.com/@bikeshaving/[email protected]/index.js";
// @deno-types="https://unpkg.com/@bikeshaving/[email protected]/html.d.ts"
import {renderer} from "https://unpkg.com/@bikeshaving/[email protected]/html.js";
console.log(renderer.render(<div>Hello world</div>, document.body));
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"lib": ["esnext", "dom"]
}
}
command
deno run -c tsconfig.json server.tsx
I think the deno-types comment is kinda annoying and will see if we can get triple-slash reference comments in the d.ts files directly.
The code throws the following error from the HTML module.
[ERROR]: Invalid module name in augmentation. Module './index' resolves to an untyped module at 'https://unpkg.com/@bikeshaving/[email protected]/index.js', which cannot be augmented.
declare module "./index" {
There is this module augmentation issue in Deno (https://github.com/denoland/deno/issues/6839), but I don’t think declaring modules based on relative/absolute path is robust in any sense. I think the best thing to do is to declare a Crank global module and use that (similar to the way TypeScript uses the JSX module).
Crank officially supports deno as of 0.3.1. You can import it as follows via unpkg.
/** @jsx createElement */
import {createElement} from "https://unpkg.com/@bikeshaving/[email protected]/crank.js";
import {renderer} from "https://unpkg.com/@bikeshaving/[email protected]/html.js";
console.log(renderer.render(<div>This is pretty cool</div>));
You need to make sure you add dom to the lib compiler option in tsconfig, or some typings will not work.
Most helpful comment
I'm feeling pretty "meh" on deno 1.0.
deps.tswill make it harder to do static analysis. (How do you automatically flag known security issues when dependencies are just URLs?) Import maps are a better solution, but they're "unstable" in deno 1.0, and they still don't address the static analysis problem.