Deno 1.14
deno.com
deno.com
Writing TypeScript code for Deno feels a lot like writing Go (which is a very good thing to me):
- opinionated build/fmt/deps
- well-designed stdlib
- no need for scaffolding files (.eslintrc, babel.config.js, jest.config.js, mocha.opts, etc.)
If that sounds good to you, try Deno!
As someone that's barely touched node for dev and always been put off by NPM and how that works (and the heavy build chain for some stuff), I find it much more palatable.
57mb is big, but not an issue when it's for personal use.
Somewhat related, I haven't used rust, but I read that it can produce an executable including the run time for edge that is less than 1mb,. I couldn't find the source, but this article shares how an extension was reduced from 12mb to 4.5mb.
Honestly, I think most the time you're looking at 10MB+ for interpreted languages that are turned into executables (through a bundling of the runtime and scripts, that is, not through compiling to something else which is likely much smaller if offered).
The complexity and size of the runtime is going to necessarily influence that size. V8 is fairly complex compared to most runtimes I think, with the JVM and maybe Mono being notable exceptions, and if you were to bundle the JVM with an app instead of just expecting them to have it installed, I imagine that would be quite large as well.
> Somewhat related, I haven't used rust, but I read that it can produce an executable including
That's actually the other thing I wanted to do with the project I built in Deno. Since it was very simple, but actually useful for me, I was also going to implement it in Rust. I've played with it a few times over the years, but never really had anything real that needed to be built in it, so this seemed like a good chance to build something real in it.
In case anyone is wondering because I mentioned it twice, the project is just reading an ini file which defines browsers, pattern matches to apply to URLs to determine which browser to load based on the URL, and a default browser. The idea being that I can send work URLs to the browser I dedicate to work that's proxied through a SOCKS connection, and other URLs get handled automatically by the browser I use for personal stuff, and I can just make the application my default URL handler. Dead simple, but very useful for my current workflow.
I was actually fairly happy with that, but it's nice to just be able to close the chrome instance with all the work tabs at the end of the day and have them all reopen when I start it up the next day, and all my work tabs are self contained and proxied through work. The only downside is I can't just click to open in Teams or Outlook, and need to copy the link and manually open it in Chrome, which is what I was aiming to fix.
I found this article[1] which seems to indicate if the node packages use ES modules you can use import them as is, or if not it says JSPM can help with that.
1: https://medium.com/samsung-internet-dev/using-node-modules-i...
The types feel soooooo good.
And to top it off there's yet another bonus to this approach: having Fetch included out of the box enabled me to mock out what eventually became my frontend requests, by running them headlessly and worrying about the form logic later.
I haven't actually gotten to using TypeScript with it personally (it's among a few things built into Deno that I've been meaning to try now that I can run them with zero config), but when writing JS I've found myself reaching for it in some of the same scenarios I (anecdotally) see people point to for Python -- bulk file manipulation, scraping, programmatic requests, etc.
I always learn something new from them.
In this case it was the existence of the URLPattern web API: https://pr8734.content.dev.mdn.mozit.cloud/en-US/docs/Web/AP...
Also that Mutual TLS is an alternative term for client authentication.
Mutual TLS is where both the server and the client must present certificates and both must verify the others' certificate in order for them to communicate. It's useful for backend server to server communications mainly.
I'd love to be able to develop backend services by pushing source code to some url as I develop, and then have the production instances of the service notified of the changes and reload themselves immediately for a super-tight feedback loop.
In theory, building this kind of workflow in Deno should be very feasible, so I'm hoping to give it a shot in the not too distant future, but I'm wondering if anyone else has already tried it?
Heck lets get this headless browser running in Ring 0 and skip to the end of Gary Bernhardt's dream.
https://en.wikipedia.org/wiki/Capistrano_(software)
10 year old gist for this exact thing: https://gist.github.com/rchampourlier/1281506/a22148264c457ebb69259261f117548569be6bef
Same exists in Node, using PM2 process monitor via rsync/ssh: https://pm2.keymetrics.io/docs/usage/deployment/
Run a command, new code is pushed to server files, you have a file-watcher daemon monitoring the directory and stopping + restarting the app, or you run stop/start as part of the deploy command.IMO the possibility for an air-tight feedback loop is _the_ killer feature for interpreted languages vs compiled ones. I can always feel my productivity plummet whenever I work in an environment that takes that away from me. I wish more people would try to take advantage of it.
It was kind of the original "serverless" - you'd often host it on a shared (multitenant) server with other users, with someone operating the web server for you and providing you with storage space. And it was a great development experience for small sites, especially for people new to web programming, and I miss it a lot.
For performance reasons people built "FastCGI" where you have a long-running process that handles multiple requests, and for software engineering scaling reasons people moved away from the model of one file on disk per URL (and URLs mostly mapping to file paths on disk), and then eventually we got the setup we have now.
Arguably a delineation like this is better, even if just a single flag separating the behavior in the server, since it allows production to not worry about some file copies/changes forcing lots of reloads that aren't needed, which isn't really a problem in most development environments.
Personally, I find Deno's "zero config" approach appealing, although I do have to fight the linter's "ban-types" rule occasionally since suggested type replacements are not equivalent.
For example, constructor signature for mixins requires `any` type that conflicts with `no-explicit-any` rule. In another case, `object` cannot be replaced with `Record<string, unknown>` when used with conditional types to mean "any non-primitive value".
If you're somebody who wants to make their ts as close to provable as possible, but also be able to handle dynamic / generative content, then you run into issues of this nature all the time with (for example) linter settings that think they know typescript better than you do, but fail to recognize that there is literally no other way to express some type-concept in typescript without using a larger feature set.
However, the argument can be made against any tool, and I'd say Deno here is the least deserving: in most cases it has just adopted the "defaults" set by tsc, eslint, or prettier, and just like them it allows ignoring these rules where necessary.
That said, I also think Deno made the right choice by enforcing these by default. Hopefully, it will fight the tide of low-quality code that plagues NPM. I do have to wrestle the linter, but it's mostly because I'm writing libraries that by themselves are pushing the limits of the TS type system, e.g. in structurae[1] I make an extensive use of mixins extending built-in objects, and mixin support is still nascent in TS. This is far less common in day-to-day production code, where, for example, using `any` or `object` is more often a sign of sloppy thinking rather than a necessity.
Precisely this. I'm compiling TS using `Deno.emit()`, which can be directly configured, but it would be nice to just configure Deno's linting/compiling behavior at the project level so that the same issues don't appear in VS Code with the Deno extension.
It's a paradigm shift, so there's always going to be some friction in migration. For your express needs, check out Oak https://deno.land/x/oak@v9.0.0
const server = Deno.listen({ port: 8080 });
console.log(`HTTP webserver running. Access it at: http://localhost:8080/`);
// Connections to the server will be yielded up as an async iterable.
for await (const conn of server) {
// In order to not be blocking, we need to handle each connection individually
// without awaiting the
function
serveHttp(conn);
} async function serveHttp(conn: Deno.Conn) {
// This "upgrades" a network connection into an HTTP connection.
const httpConn = Deno.serveHttp(conn);
// Each request sent over the HTTP connection will be yielded as an async
// iterator from the HTTP connection.
for await (const requestEvent of httpConn) {
// The native HTTP server uses the web standard `Request` and `Response`
// objects.
const body = `Your user-agent is:\n\n${requestEvent.request.headers.get(
"user-agent",
) ?? "Unknown"}`;
// The requestEvent's `.respondWith()` method is how we send the response
// back to the client.
requestEvent.respondWith(
new Response(body, {
status: 200,
}),
);
}
}Everything async await. There is an option to use a library, but it's to be deprecated,the native option is stable. Interesting import code:
import { serve } from "https://deno.land/std@0.105.0/http/server.ts";
So, Deno supports typescript out of the box or just plain JS.
Deno doesn't support npm packages, imports are done via url.
There is a window object, for whatever that's supposed to be used.
Runs sandboxed, access to filesystem etc runs on permission basis.
Access to the browser API without installing anything else.
Packages are cached, this was very annoying in nodeJS.Sounds and looks pretty damn good.
One of Deno's objectives is not to expose V8 internals, so node packages relying on those will be harder to port
And this is not a obscure need. There are cloud providers who let you run JS on a specialized and restricted API.
However, there is nothing stopping you from using Node or integrating V8 and go wild with it! (In fact I would argue that this is a solid strategy for some types of projects, where you can get the best of both (static/dynamic) worlds.
Sounds rather obscure actually. Still somewhat confused why this would be useful in Deno. Looks like it's just a repeat of what happened with Java's SecurityManager, which is now being deprecated and removed.
It is how cloudflare workers work
Will give it a try, really curious how importing works and all.
So was I, so this is what I determined, on top of the official docs.[1]
On deno run of a script, it will download referenced imports and put them into a cache directory with a hash of the name. On a UNIX-like, this seems to be in ~/.cache/deno/deps (there's also a ~/.cache/deno/gen for the TS to JS stuff). Subsequent runs do not seem to download the scripts, but instead use the cached hashed versions. There's probably a way to blow out or overwrite the cache with newer download with a deno command, but I'm not sure what it is.
Compiling bundled the cached dependencies, so they aren't downloaded on run. Importing from local files is also possible, as noted in the docs I linked.
I'm happy to be corrected to supplemented on any of that info, I would rather know the actual way it works than persist in a slightly wrong assumption. :)
I'm pretty happy with Node.js. What would be some good reasons to switch?
There's probably a use-case I'm missing, because intuitively I'd automatically classify it as bad a practice.
It seems like a minor convenience, but it might play well with inheritance or mixin classes?
Yes and no. For example, maybe you want to initialise a temporary directory on the filesystem for writing files to, for some caching mechanism. The pointer to the cache directory (maybe a const x = {}) can exist anywhere, but spinning up the directory itself in the static class block ensures that it's set up once and only once for all instances of the class. So, any instances get to reuse the directory without worrying about checking for initialisation first.
Just another tool in the toolbox, best evaluated on a case-by-case basis
There's a better example here: https://v8.dev/features/class-static-initializer-blocks
You could also use it for initialising generated constants.
class MyClass {}
export const myClassSingleton = new MyClass()
Static initialization blocks = "Constructors, for static class members/values"Static blocks only run once, like the class declaration itself:
class User {
constructor(public name: string, public age: number) {}
static {
console.log("Hello from class User static block")
}
}
const a = new User("a", 1)
const b = new User("b", 2)
Is transpiled to: class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
(() => {
console.log("Hello from class User static block");
})();
const a = new User("a", 1);
const b = new User("b", 2);I guess it's a good way to bring back that behavior with the added bonus of being useful by itself in some limited but legitimate cases (sibiling comment mentioned cache initialization, also a good point).
module.exports =
class MyClass
{ // ...
static init ()
{ // ... do something, like create and
// cache a Singleton etc.
return this;
}
} . init();
The static method init() is executed only once when the class is created and exported. You could add some check to it that causes an error if it gets called more than once.Do static blocks allow me to do something more?
> NodeJS compatibility, what is our high-level strategy, goals, next steps?
> Do we see Node and Deno co-existing, or do we want to think of Node as "legacy"? (Note, there was no clear decision on this question, it was just a conversation)
> If we could say "you can run your Express server under Deno faster than Node" would that encourage adoption? No clear answer
I really wish they go for a better compatibility with Node and sell themselves as a replacement that is strictly better.
When you load a library you can load a newer version or an older one. It's up to you. You can use both.
1. Same. 2. Better.
You can't have both. Since getting better involves change, which is the opposite of staying the same.
My current top feature request is that I wish Deno would have the same permission model for the repl.
I highly recommend listening to this recent podcast with Ryan Dahl: https://changelog.com/podcast/443
REPL is particularly useful when trying out things "live" as they come into your mind.
Otherwise you might want to check out piping support https://github.com/denoland/deno/pull/6130 Something like `echo "yourcodehere" | deno run -`
You get a fairly sane type system, good performance, easy deployment (it doesn't count as easy if it's a pain on Windows), supports single file scripts with third party dependencies, and no compilation to deal with.
There aren't really any alternatives that offer all that as far as I know.
That's good news. The main thing holding me back from seriously looking at Deno was the lack of config for the formatting. The default settings weren't right for me, and I tend to avoid projects where you have to fight the tools. I'm going to take another look now.
If you’re a hobbyist or an academic or starting a totally new project that won’t have dependencies/doesn’t need a large community of modules, then I recommend deno. Otherwise I highly recommend sticking to node until deno comes out with something to make the switch more appealing.
I believe it will be a much better if the community puts time into making a larger module pool that is upto the standard of node
Is there support on the (deno http) server-side too? Eg: easy to set up mutually trusted, private-/non-ca tls between a deno client and deno server? Perhaps via a self-signed/private CA?
TLDR: The memory is never moved, the pointers to it are just detached from one isolate, and instead passed to another.
Edit: + Electron + the JS runtime used for Windows ecosystem based on Chakra (not sure if that's still alive though?) + a few other similar ones in that vein for desktop or mobile OS'.
+ whatever is available for embedded & similar devices, (I guess there will be a few but I know little about that area).
+ various [highly] specialised business/academic/hobby/PoC/etc runtimes, but they're not realistically things that many people care about.