I’m trying to import whole modules in a javascript file.
This file pertains to the Home Assistant environment where the frontend is written in javascript, usually using LitElements and modules (cf. documentation).
For instance, the doc uses a fancy wired-card by writing:
import "https://unpkg.com/wired-card#0.8.1/wired-card.js?module";.
I've read a lot about the import call but resources are usually about local elements and it seems that I need them to be distant.
In fact, I know the plain old JS quite well but I am a bit clueless regarding importing modules (and LitElements for that matter).
For instance, I'm looking for an accordion (expansion panel), like the one of JQueryUI. I found several resources (e.g. here, here, or here) but I couldn't find how to import them easily.
What makes a module importable? Are those not or am I doing it wrong?
In standard ECMAscript, a JS file is importable if it defines a module in the new system. Kinda circular.
Basically, it should export some resources from the module file. For example, if I have a test-module.js, I can export some class using the export keyword:
class Fubar {}
export { Fubar }
// or, more concisely
export class Fubar {}
The export keyword tells the module system that the resource defined should be made available to importers.
On the flip side, if you want to import a module, you must also do so from a module! This is because module imports are async and processed before the execution (excluding the dynamic import() function).
So, if I want to import my Fubar class from another module, I can do this:
import { Fubar } from './test-module.js`
However, if I load this script as a non-module, I will get an error. Instead, I must tell the browser that the script is a module:
<script type="module" src="test-module.js"></script>
So, in short, something is "importable" if it is itself a module.
More reading:
Mozilla Dev Network article on the modules system: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
MDN article on the import keyword: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
EDIT: something I missed - to make web resources a little nicer, the import URLs can be any URL, not just a relative path. This allows importing 3rd party scripts as modules. But, those 3rd party scripts need to be modules themselves.
Related
I think I now mostly understand (in theory, at least) how ES2015 Modules work.
What I don't understand (and this is far from insignificant) is how to enable module scripts to inform my main script.
Usually, at the bottom of my HTML document, I have something like the following:
<script src="/global-script-is-a-classic-script.js"></script>
That's it. No defer, no async and no type="module".
I may wish to write some optional modules which declare functions, calculate variables and objects and then make all the declared and calculated values available to global-scripts.js:
<script src="/module-script-1.mjs" type="module"></script>
<script src="/module-script-2.mjs" type="module"></script>
<script src="/module-script-3.mjs" type="module"></script>
Naturally each of these module scripts will contain an exports statement.
But... how do I then import what these module scripts calculate into my global-script.js?
I can't use import - because that only works in a Module Script - and (unless I'm mistaken) it seems like it would be a bad idea to have global-scripts.js as anything other than a Classic Script.
So, do I now need to have two global scripts?
<script src="/global-script-is-a-classic-script.js"></script>
<script src="/module-mothership-is-a-module-script.js" type="module"></script>
Or is there an alternative standard architecture which we're all supposed to be using?
It seems you aren't really understanding the change in design philosophy with a module architecture. You don't make things global. A module imports the other modules that it needs and gets its capabilities from the import, not from some global set of functions. In a modular architecture, there would be NO global script. That's why your thinking isn't quite fitting into the modular architecture.
exports is a means of making certain entry points or data publicly accessible to anyone who imports the module while keeping everything else local to the module. One must import the module to get access to these entry points.
So, is exports intended for communication between sub-modules and modules then, rather than for between modules and a global script? That is to say modules never export, only sub-modules do?
Mostly. But, even a top level module could have exports. They wouldn't be used for anything in the project in which it was a top level module, but it could perhaps be used in a different project where it wasn't a top level module and was imported by some other module. The module architecture gets you to think about code reuse and code sharing without having to do a lot of extra work. The normal way you write your project should automatically create a bunch of reusable code.
That might have been the final piece of the puzzle I needed. So exports is just for sub-modules (and sibling-modules), then? Standalone, self-contained top-level modules don't need exports because any functionality happens right there in the module - the data never needs to go anywhere else. (Is that right?)
Yes. Unless you might want to be able to reuse that module in another project where you did import it and did want to import some entry points or data.
I may wish to write some optional modules which declare functions, calculate variables and objects and, after calculation, make all the declared and calculated values available to global-scripts.js. But... how do I then import what these module scripts calculate into my global-script.js?
You will get rid of your global script entirely in a module design. You will have a top level module that imports other modules.
So, do I now need to have two global scripts?
Nope, you get rid of the global script and you don't make things global any more.
Or is there an alternative standard architecture which we're all supposed to be using?
The module architecture:
Top Level Module
import module1
import moduleA
import moduleZ
import moduleB
import module2
import moduleB
import moduleC
import module3
import moduleA
import moduleD
This can go to any arbitrary depth as needed. Modules are cached and only initialized once so importing the same module from more than one place is perfectly fine and perfectly efficient.
Hello guys i have a little question about importing files into a single .js file.
Which way is better (best practice), what's the scenario that is used for:
import './file;'
import { something } from './file'
import * as evertything from './file'
Because i see that 2 and 3 are the same thing but different syntax(maybe Syntactic Sugar).
All three do different things.
import './file;'
That loads the file, and does not import anything. This is useful if you want to initialize that module (or add some external dependency, e.g. a css file if you use Webpack).
import { something } from './file'
That just imports something from the file, therefore a bundler could optimize all other dependencies away. I'd always try to go with that instead of
import * as evertything from './file'
That imports everything from that module under a namespace, and therefore makes treeshaking more difficult (the bundler cannot optimize it well). I'd only use that if you need everything from that dependency, or if that dependency is loaded externally nevertheless (e.g. import * as React from "react").
I guess the following MDN documentation will make you clear about those things:
import - JavaScript|MDN
As far as I know, 1st method is used when you have only one default export. 2nd is used when you have multiple default exports but you don't want all of them to load and want only few of them. 3rd is the case when you want everything under a single object (which can be used similar to namespace in other programming languages).
Here comes silly and simple question:
I am new to this whole webpack tools.
I have been trying to build a simple web-app using typescript and webpack. In the old days, I created typescript and compile them without bundling them.
With webpack, I already installed necessary loaders, typescript, and jQuery.
The problem is, I have 3 typescript files:
main.ts -> imports all assets (images, css) and other typescripts
functions.ts -> consist all of my custom functions/modules
ui-controller.ts
in functions.ts I always created namespaces such as:
module Functions{
export module StringTools{
export function IsEmpty(): boolean{
//some code
}
}
}
in the browser, I knew that the snippet code above will be called, but it is not recognized in the main.ts (in the run time) even thou I already import it.
This is how I import it in main.ts:
import '.src/functions'
Any suggestion how I can resolve this?
Typescript module keyword is confusing, and in version 1.5 it was indeed changed to namespace to better reflect it's meaning. Look here.
Namespaces are also called internal modules. They are meant to be used when your files are evaluated at the global scope. You can use typescript playground to see how namespaces are transpiled. The point is - namespaces are not modules.
Webpack however, does not evaluate files in the global scope, it evaluates them inside a function in order to provide real module behavior.
So what does make your typescript file into a module? the keywords export and import (but not inside a namespace like in your example).
Typescript will see those keywords, and will transpile them into commonjs\AMD\es6 require or define statements, according to your configuration in tsconfig.json. Now you have "real" modules. Then it's Webpack's job to do something (lots of info about that online) with those modules so that they will work in the browser where you don't have modules, but that part is not related to typescript.
TL;DR -
So how would you do this in Webpack?
/* functions.ts */
export function IsEmpty(): boolean{
//some code
}
and
/* main.ts */
import {isEmpty} from './functions';
if you want better code organisation as suggested by your use of module StringTools, just split into different files. You can read more about es6 import syntax for more info.
The first part of this answer is that your main module (which has been replaced with the namespace keyword) is not exported... so there are no exported members for your functions file.
export namespace Functions { //...
Part two of the answer is that if you are using modules, you don't need to use namespaces as the module is enclosed within its own scope.
Working version of the file as you designed it, I'd say drop the wrapping namespace:
functions.ts
export namespace StringTools{
export function IsEmpty(): boolean{
//some code
}
}
This Meteor template code is the default generated when meteor create myApp is invoked. In main.js the first 3 lines are:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
But when I comment them out, the app still runs. Reading the docs could not answer my question, Why do we need the import statement if the app still runs without them? Thanks
Earlier versions of Meteor relied heavily on using the global namespace for accessing shared libraries. As of Meteor 1.3, you can now use Meteor's ES2015 module support. This means you can use import/export functionality to expose access to various parts of your codebase, without having to rely on globals. Using imports/exports is now the preferred/recommended way of referencing parts of your application, so meteor create functionality was updated to demonstrate this. As you mentioned, you can remove the import statements above and you will still be able to access Template and ReactiveVar globally (for backwards compatibility). It's important to note however that this might change in the future - Meteor has fully embraced ES2015 module support, and could potentially drop the use of globals completely (well, to the extent possible).
One more thing to note - Meteor 1.3 also introduced new "lazy-loading" functionality, wherein application code stored under an /imports directory will no longer by eagerly loaded when the application starts up. Code stored under an /imports directory will only be loaded if it's referenced by an import statement somewhere else in your codebase. See Special directories for more info.
I have gone through 2ality article on Modules, however, I am confused, how does the system know to treat a module as a module?
import React from "react";
import { hello } from "./hello.js";
var Ctrl = React.createClass ({
render : function () {
return (
<div .... random data
></div>
);
}
});
export default Ctrl;
To me, a module is just a file with global code written in it. We reference the module via its filename.
However, I wonder how does this all gel together when we build the production build.
How does the system know that this is a module & not just global varaibles being declared?
Is it the import / export commands that actually make it say: 'aha, this is a module!'
Excuse the newbie question.
Is it the import / export commands that actually make it say: 'aha, this is a module!'
Yes!
More precisely, the import keyword instructs the JavaScript engine (or transpiler) to load an external file as a module.
if by system you mean the browser, it doesn't know, you normally use another tool that implements the idea of modules for you, and it transforms (puts in code) that act as a module system for you that the browser understands.
some tools like do this is require in node, browserify, webpack
that*, not like