How to use require and module.exports in Node without repetition? - javascript

I have created a class file in Node called chart.js that relies moment.js and a bunch of other external dependencies:
var moment = require('moment');
...
var Chart = {
doSomething: function() {
} ...
};
module.exports = Chart;
Now I want to use this chart.js module in my index.js file, so I am importing it as follows:
var chart = require('chart');
chart.doSomething();
But this gives me import errors:
ReferenceError: moment is not defined
Do I need to re-include all the require('moment') statements at the top of index.js too?
Surely I should be able to change the requirements for the chart file without having to amend the index file too?

No, you don't need to specify require('moment') in every file. Make sure moment JS library is installed correctly and that it is in your node_modules directory.
For Node modules installed with npm, you can require them with require('moduleName'), so require('moment') is fine. But for your own modules, you have to specify the relative path and the file name. So, assuming index.js and chart.js are in the same level, in your index.js you would do require('./chart.js').
Other notes: don't capitalize variable names unless you are using a class constructor function. In your code you are using simple object literal, not a constructor, so there's no need to capitalize the variable name, Chart.

Related

Is there a way to assign the content of a file to a specific variable using webpack?

Is there a way to assign the file contents directly to a variable/method without webpack generating an additional variable?
Currently webpack does something like this:
index.js
import scss from './styles.scss';
console.log(scss);
output.js (actual)
const styles = '...';
console.log(styles);
I want webpack to return the content of the styles.scss file directly to the console.log() method in the output without adding styles variable.
output.js (expected)
console.log('...');
I'm currently using my custom loader for reading .scss files:
css-loader.js
const sass = require('sass');
module.exports = function(source) {
const result = sass.compile(this.resourcePath);
return 'export default `\n' + result.css + '\n`';
};
I know there is a way to do this using the require() function but it generates a lot of extra code coming from webpack. Is there any other better way to do it?
So it's really a scoping issue. So there's no real requirement to not wanting webpacks default behaviour.
Webpack has a few ways how to do that. See this other answer for how to define a global variable, which is Webpacks way of doing what you want to do.

How do I call a function in an external js file using typescrpt

We are trying a POC of adding Typescript and Webpack to our Angularjs project.
I am able to get my webpack bundle to generate, however at runtime the program cannot find the various functions in my validator.js. Can you please offer some advice?
login-view.components.ts
declare var findFormNode: any; //function in validator.js
//LogInUser
self.login = function ($event, command) {
if (findFormNode($event.target.id)) {
...
}
}
main.ts is importing the file
import "./../../../CommonStaticFiles/include/js/Validators.js";
bundle.js
eval("/* WEBPACK VAR INJECTION */(function($) {/*\r\n\r\n VALIDATORS\r\n\r\n ... n\n\nfunction findFormNode(
error
ReferenceError: findFormNode is not defined
at LoginController.self.login (login-view.component.ts:28)
at fn (eval at compile (angular.js:NaN), <anonymous>:4:267)
at callback (angular.js:29019)
In order for your functions to be properly imported, there are few things that you have to make sure of.
First, make sure you are exporting your functions correctly. Here's an example of how to export a function from Validator.js:
export const validateFunc1 = ():void => {};
Next, you have to make sure you are using proper import syntax. In order to import the function above, you would do the following:
import {validateFunc1} from "./../../../CommonStaticFiles/include/js/Validators.js";
Alternatively, if you want to import all exported functions at once, then you can use this syntax:
import * as validatorFuncs from "./../../../CommonStaticFiles/include/js/Validators.js";
Lastly, check that the location of Validators.js is correct. It's a common mistake to be looking in the wrong directory. Your code editor can usually help you find the right path to use.

How should I define a global TypeScript variable in a definition file so that it can be imported?

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.

How to use plain js lib in a ts angular 2 app

I'm building an Angular 2 (rc.4) app with TypeScript and I would like to use D3.
I've installed D3 through npm install, but this is a js module without .d.ts file. However, I've found a .d.ts file here.
What I do now (a component):
import d3 from 'node_modules/d3/build/d3.min.js';
//<reference path="../declaration/d3.d.ts" />
//[...]
export class Test {
constructor() {
this.object = this.d3.select(...);
}
}
If I set a break-point on that line in the TS file, I can execute everything just fine. However, the mapped .js version of this file was converted to:
var d3_min_js_1 = require('node_modules/d3/build/d3.min.js');
[...]
this.object = d3_min_js_1.default.select(...);
The d3_min_js_1 object exists, but there is no 'default', so it throws a undefined exception...
How can I get this mapping right (I'm pretty sure d3.d.ts does nothing) or how can a use the plain javascript in the TS-file (without it getting f*cked up by the compiler)?
I hope this plunker will help you: https://embed.plnkr.co/qM3qrk3swvalQFBh1Db1/

React - webpack exports

Edit - Answer: encapsulating the imports work as required:
# index.js
var myLibrary {
ProfileApp: require('./components/ProfileApp.react'),
ProfileStore: require('./stores/ProfileStore'),
}
module.exports = myLibrary;
I can now do
var lib = require('myLibrary');
var ProfileApp = lib.ProfileApp;
End of edit
I have developped a react/flux libray which I need to package using webpack. I do this for the first time and my exports seem wrong... (the library itself works well).
My (simplified) index.js file is
# index.js
module.exports = require('./components/ProfileApp.react');
module.exports = require('./stores/ProfileStore');
...
The code is correctly compiled and installed in node_modules, but does not work when imported.
# whatever.file.doing.imports
var myLibrary = require('myLibrary'); # works well
var ProfileApp = myLibrary.ProfileApp; # works only if I call it --> myLibrary.ProfileApp()
var ProfileStore = myLibrary.ProfileStore; # does not work and myLibrary.ProfileStore() raises "is not a function error"
I think my exports in index.js should use another syntax. For instance, React Router (https://github.com/rackt/react-router/blob/master/modules/index.js) uses
export Router from './Router';
# which can be simply instantiated writing
var Router = ReactRouter.Router;
This syntax raises an error when used in my library. Do you know if I have to use plugin to be able to use this syntax, or if I can write it differently?
Thank you very much!
The special export syntax that React Router uses is from ES6 and is "transpiled" by the Babel loader that you see in use in the webpack config on line 23. Also note that that line only applies to files that have a ".js" extension. Since you have files with ".react" extensions, you may need to change that line.
Unfortunately that does not explain your issue with having to call ProfileApp as a function. Maybe if you posted the code for the ProfileApp and ProfileStore, that would help.

Categories