I am using the following pattern for of angular module definition:
define(function(require) {
var moduleId = require('module').id;
var angular = require('angular');
var ngModule = angular.module(moduleId,
[require('angular-xx1'), require('angular-xx2')]);
ngModule.directive('myDirective', {/*...*/ });
return moduleId;
});
This way, by exporting module name I can easily manage loading of the scripts during development and building for production is automatically handled by require.js. Furthermore I don't have to worry about module naming as moduleId is guaranteed to be unique.
Yesterday I have stumbled upon BabelJS (https://babeljs.io/) and its AMD loader plugin. It works very nicely but I have trouble using only ES6 syntax to manage my loading. The best I can come up with is having a mixed AMD/ES6, depending on the transpiler wrapping my code in the right AMD definition.
import angular from 'angular';
import {id} from 'module';
export default id;
let ngModule = angular.module(id,
[require('angular-xx1'), require('angular-xx2')]);
ngModule.directive('myDirective');
I would love not to depend on any assumptions of a module loader here so I would love to get rid of having to write require and some way to get unique module id with importing id.
Related
I have a config.ts and I do
module.exports = { something: 123 }
when I import like import { something } from './config.ts' I got error of config.ts' is not a module, what's the issue? my typescript is configured rightly and it's working in other places.
If you're using import { something } from './config.ts', you're using JavaScript modules, but your code in config.ts is using CommonJS modules. Some bundlers and such may let you mix them, but it's best not to.
To make config.ts a JavaScript module compatible with that import declaration (which expects a named export called something), change it to:
export const something = 123;
Or, of course, to use config.ts via CommonJS, your code using it would be:
const { something } = require("./config.ts");
...but given the error you're getting, I think your project is set up to use JavaScript modules (import/export), which here in almost 2021 is probably best (now that we have dynamic import to handle the cases where static modules don't quite do the job).
I would like to import My JavaScript Model from another file but I don't want to hard code part of that model. (I am using WebPack)
For example:
Module Location is src/module/something.js
In another javascript file, I want to import that using lazy load:
module = () => import('#/src/module/something');
The way I want to import it is:
let path_of_module = '#/src/module/something';
let module = () => import(path_of_module);
I am getting stuck in webpack building process.
How can I import a module using javascript variable which show that path of the module?
Seems like it is not allowed to have dependencies provided as expressions:
Critical dependency: the request of a dependency is an expression
As I don't know your use case, I just guessing what might help you:
You could lazy load your modules to access them only when they are needed.
const MyModule = () => Promise.resolve(import('../module/MyModule.js'));
In this case you would need to write some kind of switch to determine which module needs to load.
About the framework (while I think the problem itself does not heavily rely on that): Angular 2 with Webpack
There is the library Leaflet.heat which relies on simpleheat. I got the missing type definitions under control.
I'm importing the libraries in my vendor.ts
[...]
import 'simpleheat';
import 'leaflet.heat/src/HeatLayer';
[...]
Inside of the HeatLayer class, the function simpleheat:
[simpleheat.js]
if (typeof module !== 'undefined') module.exports = simpleheat;
function simpleheat(canvas) {
...
is called. However, the HeatLayer module file does not require simpleheat inside it's file.
Thus, creating an instance of L.HeatLayer works, but the execution of the respective code in it's function fails with
ReferenceError: simpleheat is not defined
Now, adding (for testing purposes) simpleheat = require('simpleheat'); into the HeatLayer file (a vendor), it works.
Understandably, I don't want to modify a vendor file.
Question:
What options do I have, to make the function simpleheat accessible from inside the HeatLayer module?
One Solution I just found:
Change the vendor.ts to the following:
(<any>window).simpleheat = require('simpleheat');
import 'leaflet.heat/src/HeatLayer';
Are there others/better?
I have an external JS library with a global parameter:
function Thing() { ... }
...
var thing = new Thing();
There is a TypeScript definition file, so in thing.d.ts:
declare var thing: ThingStatic;
export default thing;
export interface ThingStatic {
functionOnThing(): ThingFoo;
}
export interface ThingFoo {
... and so on
Then I import this into my own TS files with:
import thing from 'thing';
import {ThingFoo} from 'thing';
...
const x:ThingFoo = thing.functionOnThing();
The problem is that transpiles to:
const thing_1 = require("thing");
...
thing_1.default.functionOnThing();
Which throws an error. I've asked about that in another question, and the suggestion is to use:
import * as thing from 'thing';
That doesn't fix it - it gives me thing.default in TS but then that's undefined once transpiled to JS.
I think there's something wrong with thing.d.ts - there must be a way to define a typed global parameter that can be imported.
How should I write thing.d.ts so that it represents the JS correctly and doesn't transpile to include default or other properties not actually present?
If the only way to use that library is by accessing its globals (as opposed to importing it as node module or amd or umd module), then the easiest way to go is have a declaration file without any exports at top level. Just declaring a variable is enough. To use it, you have to include that declaration file when compiling your typescript code, either by adding it to files or include in tsconfig.json, or directly on command line. You also have to include the library with a <script> tag at runtime.
Example: thing.d.ts
declare var thing: ThingStatic;
declare interface ThingStatic {
functionOnThing(): ThingFoo;
}
declare interface ThingFoo {
}
test-thing.ts
const x:ThingFoo = thing.functionOnThing();
can be compiled together
./node_modules/.bin/tsc test-thing.ts thing.d.ts
the result in test-thing.js:
var x = thing.functionOnThing();
See also this question about ambient declarations.
Note: there are module loaders out there that allow using global libraries as if they were modules, so it's possible to use import statement instead of <script> tag, but how to configure these module loaders to do that is another, more complicated question.
I'm having trouble importing Showdown as a vendor. When I compile, I get showdown is not defined in the browser console. Since it is a vendor package, I don't think I can import it inside of app.module.ts. Do I need to declare a custom typing for it? The package is all in js. I am running on Angular2 RC5. Thanks!
home.service.ts
import 'showdown/dist/showdown';
declare var showdown: any;
private extractData(res: Response) {
let body = res.json();
var converter = new showdown.Converter(),
originalBody = window.atob(body.content),
body.title = converter.makeHtml(title);
}
vendor.browser.ts
import 'showdown/dist/showdown';
I'm not familiar with the Showdown, but if you want to import it in the code you need to have type definition files. If you use TypeScript 2.0, you can simply install it from npmjs.org. I just checked - they have the type definitions for Showdown in the #types organization: https://www.npmjs.com/search?q=%40types%2Fshowdown
Just run npm i #types/showdown --save-dev.
If you use older TypeScript, install the declarations with Typings.
Don't forget to add a script tag for Showdown in your index.html.
In this sample app I use JQuery implicitely, but don't need to import it though:
https://github.com/Farata/angular2typescript/tree/master/chapter2/auction
Solution was to employ typings mentioned by Yakov Fain
import {Converter} from "showdown/dist/showdown";
const converter = new Converter();
var body.title = converter.makeHtml(title);