Deno - Importing TypeScript into a JS file - deno

In Deno, to import a TypeScript module, does your own code file have to be TypeScript? Or does Deno auto convert TypeScript to javascript before the module gets imported?
I want all my code files to be EcmaScript modules (js or mjs, but not ts).
Unlike everyone else these days, I want to avoid using TypeScript in my own code. I dislike the rigidity of static types and Typescript is not part of the EcmaScript standard. EcmaScript alone has all I need to manage big projects. To me, TypeScript is an antiquated technology that has not been necessary since the advent of ES6 modules. The types of problems TypeScript addresses are problems I do not have.

You can write your own code with JavaScript.
Suppose you have or are using a TypeScript file/module numbers.ts:
export function isEven(n: number): boolean {
if (n % 2 != 0) {
return false
}
return true;
}
You can import and run it with an app.js JavaScript script:
import { isEven } from "./module.ts";
const one = isEven(1)
const two = isEven(2)
console.log(one)
console.log(two)
Deno does the TypeScript convertion to JavaScript internally. The process is the same when using standard or 3rd party libraries. The folks at the Deno project went even further by adding it as a goal:
https://deno.land/manual/introduction
Browser compatible: The subset of Deno programs which are written
completely in JavaScript and do not use the global Deno namespace (or
feature test for it), ought to also be able to be run in a modern web
browser without change.
Name resolution must be fully qualified. There's a whole lot more about referencing type definitions in this dedicated page for using TypeScript:
https://deno.land/manual/getting_started/typescript
Deno supports both JavaScript and TypeScript as first class languages
at runtime. This means it requires fully qualified module names,
including the extension (or a server providing the correct media type)
Example:
import { config } from "https://deno.land/x/dotenv/mod.ts";
Following my example above you can use the bundle command to generate a single JavaScript file with all the dependencies. Bundling it will take my app.js and module.ts files and create a new file app.bundle.js which is JavaScript.
https://deno.land/manual/tools/bundler
$ deno bundle app.js app.bundle.js
Bundling file:///home/pomatti/projects/deno-sandbox/app.js
Emitting bundle to "app.bundle.js"
3111 bytes emmited.
$ deno run app.bundle.js
false
true
It can even be loaded in the browser:
Bundles can also be loaded in the web browser. The bundle is a
self-contained ES module, and so the attribute of type must be set to
"module". For example:
<script type="module" src="website.bundle.js"></script>
As for ECMAScript modules I would like to point out that TypeScript implements it as well.
https://github.com/microsoft/TypeScript/issues/2242
https://www.staging-typescript.org/docs/handbook/modules.html
Starting with ECMAScript 2015, JavaScript has a concept of modules.
TypeScript shares this concept.
Now, the "static type" discussion falls out of scope of this forum so I won't touch it here, but I believe I covered everything else.

Related

Module resolution not consistent with esm and non esm files

I have a project setup where I have a web app that rely on few Firebase SDKs that is Webpacked and served via webpack dev server.
From what I could gather without getting into too much details is that there is a final dependency that have both general index, and es2017 index files
there are intermediate dependencies that also have both, like the app and some that have only es2017 for example the messaging, and some only general index files.
The problem I have is that, and I have debugged for a very long time, from my application level when I import an intermediate dependency in different files, in some cases it takes the general index file, and in some the es2017 of the same library.
So in the error stacktrace here I am trying to initialize the messaging service of Firebase: (ignore for a moment the missing promise reject)
at Provider.getImmediate (index.cjs.js:153) // in component lib
at Module.getMessagingInWindow (index.esm2017.js:1155) // in messaging lib
at new MessagingWrapper (MessagingWrapper.js:76) // in my application
at FirebaseSession.push.56916.FirebaseSession.getMessaging (FirebaseSession.js:96)
at PushPubSubModule_Class.<anonymous> (PushPubSubModule.js:118)
at step (PushPubSubModule.js:63)
at Object.next (PushPubSubModule.js:44)
at fulfilled (PushPubSubModule.js:35)
When the messaging module is initially loaded it also accessed the component lib and uses the correct es2017 index file, but at a later point when I am trying to actually get the instance of the Messaging service it goes to the other general index file.
in all cases I use the import the same as in import {somthing} from "#firebase/messaging"
I never really had to worry about these things and might miss something fundamental, but this feels like a webpack bug in predetermine which module to load from the nested lib...
do you know of a way I could FORCE webpack to resolve es2017 index file?
or should I open a bug?
More details:
This is the transpiled code of my MessagingWrapper file:
line 71: goes to the correct es2017 index file in the messaging lib and the correct es2017 in the component lib
where as line 76: goes to the correct es2017 index file in the messaging
line:
and here line 1155: actually goes to the firebase/app lib es2017 file to resolve the provider, comes back to line 1155 and then call to getImmediate which ends up in the general index file in the component lib, as you can see below:
How do I fix this?
#firebase/* packages are internal and you shouldn't be importing them within your code as warned on each of their npm directory listing. As you encountered, this can lead to issues with module resolution as you essentially skip the internal setup steps by accessing the internals directly.
Instead, use the public API interfaces via firebase/* (for the modular SDK on v9+ or legacy SDK v8 and lower) and via firebase/compat/* (for the legacy SDK on v9+).

Using Lit with Javascript and no build tools

I am building a desktop app that monitors some things and generates data about what it is monitoring. When the user wants to interact with the data the app starts a very simple web server. The server serves static pages and has a basic http API to serve the data. I use html as a universal UI, the user uses their browser to view and interact with the data.
I would like to rewrite my html/css/js into a component based web app using Google's Lit 2. I like the idea of plain web components but I noticed that Lit offers some great additional features. Not surprisingly, most of the Lit docs are geared toward a more traditional web environment with a build step. I want to see if I can keep my server as simple as possible and avoid traditional backend tools (typescript compilation, minification, etc). I would like to replace my current static html/css/js with Lit components in a series of simple js files.
Currently, my server serves my pages from a 'public' directory and has a minimal http API:
- public/
-- js/
-- css/
-- index.html
How should I use Lit in a system without a build step? What is the minimum set of Lit files I would need to serve along with my own javascript classes that inherit from LitElement?
2022 update: Starting with version 2.2.0, lit is also available as a pre-built bundle, see https://lit.dev/docs/getting-started/#use-bundles
<simple-greeting name="World"></simple-greeting>
<script type="module">
import {html, css, LitElement} from 'https://cdn.jsdelivr.net/gh/lit/dist#2.4.0/core/lit-core.min.js';
export class SimpleGreeting extends LitElement {
static get styles() {
return css`p { color: blue }`;
}
static get properties() {
return {
name: {type: String}
}
}
constructor() {
super();
this.name = 'Somebody';
}
render() {
return html`<p>Hello, ${this.name}!</p>`;
}
}
customElements.define('simple-greeting', SimpleGreeting);
</script>
Original answer:
The Lit team doesn't provide a pre-built bundle as of 2021-08-01, you have to build yourself (to resolve the bare module specifiers, such as import .. from 'lit-html', which are not supported by browsers yet)
If you're fine with relying on a third-party CDN and supporting modern browsers only, skypack is very useful, as you can simply import lit from 'https://cdn.skypack.dev/lit'; in a web page.
(If you open https://cdn.skypack.dev/lit and then the pinned URL specified in comments, you can see there are only 5 JS modules involved, so extracting them from lit's source by hand to host as part of your application shouldn't be very hard either.)

open-wc how to use web components in a legacy application

I had a look at the open-wc generator. I can generate web component libraries and web component application but the generated README file and the documentation does not contain a description how to import a web component library into another library or into an application so that the library or application can use the dependency as a web component. Is there a sample but non trivial application build with open-wc that I can use to learn from?
My primary interest is to import several web component into a legacy application that does not use npm and rollup by itself. What would be the best way to do that?
What I have tried to do. I have created a library litelement-demo by running
npm init #open-wc
and I have created an application in the similar way. I have opted for using typescript in both cases. The README.md of libelement-demo states that it can be used in this way:
<script type="module">
import 'litelement-demo/litelement-demo.js';
</script>
<litelement-demo></litelement-demo>
I have added this snippet to the application's index.html and run
npm i --save ../litelement-demo
npm run build
but the 2nd command fails with the error message
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
litelement-demo/litelement-demo.js (imported by inline-module-index-1.js)
The link in the error message does not help and neither the open webcomponent documentation nor the generated README.md files.
Typical web component is basically a class as follows:
// You can also use some external library and inherit from its base class.
// For example: LitElement
class BasicSetup extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// Template/DOM generation
}
// One or more methods...
}
// Registration
customElements.define('basic-setup', BasicSetup);
Have a look at a registration statement. Simply add this file in your HTML scripts section and you are done. You do not have to integrate with any existing library or solution. Wherever, you have HTML, you can simply use it as
<div>
<p>My Awesome web component</p>
<basic-setup></basic-setup>
</div>
You can also initialize the element with JavaScript using customElements.get(name) method if you do not have access to BasicSetup class reference.
// Get reference to basic-setup class assuming it is already registred.
const ClassRef = customElements.get('basic-setup');
// Initialize using constructor
const myCustomElm = new ClassRef();
// or use document.createElement
const myCustomElm = document.createElement('basic-setup');
document.body.appendChild(myCustomElm);
Since your legacy application doesn't use npm, you don't need to do anything with it an npm.
Just add in the head
<script type="module">
import 'litelement-demo/litelement-demo.js';
</script>
and then use
<litelement-demo></litelement-demo>
somewhere in your html. Nothing else needed to start working

Next.js - import server-side package in a file contains both server-side and client-side functionality?

Let's say I have a file named utils.js, containing two functions s and c.
s is a server-side function (Being called on an /api endpoint handler), and uses mongodb package.
c is a client-side function (will be bundled and sent to the browser).
When compiling the app using next build, will it cause any issues?
Does webpack know to bundle only part of a file/module? (considering server-side functions and imports as a "dead code" since they only being called from a server-side code)
Thanks
If you need to know which functions get bundled to the client & which ones to the server, there's an easy way to know this → https://next-code-elimination.now.sh/
Just copy & paste the contents of your file into it & you'll see which code gets bundled to the client & which code is bundled to the server. If you have imports then make sure to put all the imports in one file so you can see how it works.
The thumb rule is:
Anything like getServerSideProps, getStaticProps & getStaticPaths will be removed from the bundled code. If you import anything from a file that uses server-side code like fs but doesn't use it in any of the above 3 functions, then it won't be removed (check at Next Code Elimination Tool) & will give you an error.
The tool is the answer. I copy-pasted my file in it & found the answer in an instant.
I think there will be errors but not in the build time. It is likely issues will happen in the run time. You won't be able to access file systems on the client side just like how you can't access the window object on the server-side.
In my current project, we have utility functions for both the server-side, client-side, or universal. All server-side functions are called in getServerSideProps to make sure they work as expected. All your server-side code in getServerSideProps will not be imported as part of the client-side bundle if that's what you mean by "dead code". According to the Next.js
Note: You can import modules in top-level scope for use in
getServerSideProps. Imports used in getServerSideProps will not be
bundled for the client-side.
This means you can write server-side code directly in
getServerSideProps. This includes reading from the filesystem or a
database.
I'm not aware of a way you can ask webpack to bundle part of the file or execute a subset of import statements.
I hope that provides some help.
Reference:
Docs - getServerSideProps
Custom Webpack Config

How do I consume a polymer lit-element?

I have a litElement that I will need to consume from another domain. My browser is Chrome, I am using 'polymer serve' and navigating directly to the es5-bundle.
The lit-element is very simple. Just some static text.
When I use 'polymer build' my entry HTML page gets compiled (or transformed). I see a reference to 'custom-elements-es5-adapter.js' is added, as well as other custom JavaScript. When I navigate to this entry page (in the build folder) everything works. However, if I replace that compiled version with the original uncompiled version I get an error in the chrome console 'define is not defined'.
Eventually I will be calling this from another domain and will not be building the HTML it with polymer.(I have already tried it cross-domain and it's not working)
What do I need to include in the client to consume the polymer lit-element?
Here is what I have:
<body>
<my-element></my-element>
<script src="../node_modules/#webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<script type="module" src="./components/my-element.js" crossorigin=""?</script>
</body>
lit-element requires a transform step. The files the browser consumes must be transformed. If you want to deploy your original source files, the web server to which you deploy them needs to perform the transform step itself (as polymer serve does).
Source: lit-element README:
LitElement is published on npm using JavaScript Modules. This means it
can take advantage of the standard native JavaScript module loader
available in all current major browsers.
However, since LitElement uses npm convention to reference
dependencies by name, a light transform to rewrite specifiers to URLs
is required to get it to run in the browser. The polymer-cli's
development server polymer serve automatically handles this transform.
Tools like WebPack and Rollup can also be used to serve and/or bundle
LitElement.
The lit-element README has an example that will run in a browser with no transform steps. The example loads the lit-element library as modules from unpkg like this:
<script type="module">
import {LitElement, html} from 'https://unpkg.com/#polymer/lit-element#latest/lit-element.js?module';
class MyElement extends LitElement {
...
</script>
<my-element></my-element>
That method is useful if you want to try out lit-element with less messing about, but the Polymer team doesn't recommend doing this in production; AFAIK unpkg has no guarantees about uptime or performance.

Resources