using a module in another module. module.exports is empty object - javascript

I have a module that I would like to use in a different project. It is compiled using webpack3. In the second project I've linked to the first module and that seems to work, except when I require the module, it always comes back as an empty object.
tsconfig options
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"allowJs": true,
"lib": [
"es2015"
]
}
}
dist/index.js (shortened)
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Test = /** #class */ (function () {
function Test() {
}
Test.prototype.test = function () {
console.log('works');
};
return Test;
}());
exports.Test = Test;
/***/ })
/******/ ]);
package.json (shortened)
{
"main": "dist/index.js",
}
What this boils down to is a module called "test", a class called Test that also includes a method called Test.
If I run module.exports on the first project, it's an empty object.
In the second project that has linked to it and has it in it's node modules.
const test = require("test");
console.log(test); // {}
If I copy the code from another node module, and paste it overtop of the dist/index.js, it does return what is expected.
Does the exported webpack config need to also be imported via webpack? I want it to be used in many projects regardless of if they are using webpack.
Thanks for any help, I feel like I'm almost have it but I'm not quite there.

maybe this github issue can help you
Can't require bundle on node.js
set these in the webpack config file
target: "node"
output.libraryTarget: "commonjs"

EDIT:
It's important to outline the package in your webpack.config
https://stackoverflow.com/a/44542254/3425961

Related

Export TS to support ES6, CommonJS, and HTML <script> tag

I'm coding up a TS library that exports an object like this:
export const MyLibName: SDKExport = { ... }
This library will be distributed on npm and I want others to be able to import it regardless of their setup, i.e. it should be able to be used in the following ways:
// ES6
import { MyLibName } from './myLib';
// CommonJS
const { MyLibName } = require('./myLib');
// Browser
<script src="https://cdn.jsdelivr.net/npm/myLib/dist/dist.min.js"></script>
<script console.log(MyLibName) </script>
The browser part is proving to be the most tricky since it requires "polluting" the global namespace with the MyLibName object. I can do that, but it's unclear to me how to do it in a way that doesn't pollute the global namespace when importing the library explicitly using CommonJS/ES6.
Here's my tsconfig.json:
{
"compilerOptions": {
"lib": ["ES2019"],
"module": "es6",
"target": "es5",
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"sourceMap": true,
"outDir": "build",
"strict": true,
"noImplicitAny": true,
},
"include": ["./**/*.ts"],
"exclude": ["node_modules", ".vscode", "test"]
}
It's clear that the script you're importing in the browser must be a different thing than your CommonJS/ES6 import if you want one to pollute the global namespace but not the other. Just create a file like this one and use your bundler on it to create a "browser build" of your library:
import { MyLibName } from './myLib';
window.MyLibName = MyLibName;
(You seem to have a bundler/minifier in your project already so I won't go into detail on how to set up those.)
I tried using the approach suggested by Vojtěch Strnad with browserify, but encountered issues that were hard to debug due to all the extra code that browserify adds to the exported files. I'm accepting that answer as it's the correct one for complex codebases.
For my own project, which only includes a single file, I found that it worked well to export the TS code using the "module": "ES6" TS compiler options and run sed -i 's/\export //g' dist/index.js to remove the export keyword. That way, the exported file simply has const MyLibName = { ... } and thereby adds the object to the global namespace.

Importing Node.js SDK into Typescript running in Node server gave error "ReferenceError: require is not defined"

I'm working on a Node.js SDK for server side usage, and running into this issue "ReferenceError: require is not defined" when trying to import it into my express app using Typescript. Initially I didn't have .d.ts files generated so I imported Typescript and generated the declaration files, but still got the error. My index.js in the SDK package:
const myDep = require('./myDep');
const client = function (sdkKey) {
const c = {};
c.do = (user) => {};
return c;
}
module.exports = client;
The generated index.d.ts file looks like this:
export = client;
declare function client(sdkKey: any): {
do(user: any): void;
};
This is the tsconfig.json in my SDK package:
{
"include": ["src/**/*", "src/index.d.ts"],
"compilerOptions": {
"resolveJsonModule": true,
"target": "es6",
"lib": ["es6"],
"module": "commonjs",
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"moduleResolution": "Node",
"outDir": "./dist"
}
}
I'm using npm link to import it in my node server running typescript, and using import in my app.ts file with
import * as mySDK from 'my-node-js-sdk';
Figured it out in the end and it was fixed by adding a index.d.ts file for type declaration. Also found a couple places in my project where I was using ES6 exports instead of module so had to fix those as well.

Typescript classes bundle with webpack

I have written a project on Typescript and setup to bundle it with webpack.
Main functionality is wrapped in one Main class, but it imports also other classes.
Need to export Main class and all dependent in to one bundle.js library to use in in other sites.
I've tried to bundle classes in separate project (without webpack just tsc).
this is tsconfig.json:
{
"compilerOptions": {
"module": "amd",
"target": "ES2015",
"declaration": true,
"outDir": "./dist",
"outFile": "./dist/index.js",
},
"include": [
"src/**/*"
]
}
but it is not usable since the error:
ReferenceError: define is not defined
compilled code contains edfine
define("Globals", ["require", "exports"], function (require, exports) {
and also with webpack but not sure have correct setup
the bundle file start with
(function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
in other words I have some classes:
Main.ts
A.ts
B.ts
C.ts
and I expected to get bundle.js file and use like this:
<script type="text/javascript" src="mylib/dist/index.js"></script>
//...
var a = new Main();
but stuck with understanding how it should Typescript and Jsvascript work together.
Will appreciate any help
Update:
Managed to solve with webpack. Main is asccessible from entry app.ts when compiled. So inside app.ts added window.onload handler and assigned class to window scope.
window.onload = function () {
window['MyClass'] = Main;
May be missing something but couldn't find good documentation about writing library on TypeScript for browsers.
Update2:
Ok. found answer. webpack option library works fine.
output: {
filename: "bundle.js",
path: __dirname + "/dist",
library: "MyMainClass"
},
also had to change tsconfig.json target option from es6 to es5
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "*": ["types/*"] },
"lib": [
"dom",
"es6",
"dom.iterable",
"scripthost"
],
"module": "commonjs",
"target": "es5"
},
"exclude": [
"node_modules"
]
}

TypeScript -> JavaScript for browser: exports/require statements

I want to switch from JavaScript to TypeScript for our web app's scripts. However, when generating the JavaScript it always puts the following lines on top of the script:
"use strict";
exports.__esModule = true;
var $ = require("jquery");
I receive browser errors for this. How to prevent TypeScript from doing so?
I read TypeScript: Avoid require statements in compiled JavaScript but it can't be the answer to switch to "any", this forfeits the whole TypeScript idea.
I also read Typescript importing exported class emits require(...) which produces browser errors but this still generates the <reference... stuff into the JS file, which is also not what I want.
How to create "clean" JS files?
My tsconfig.json looks like this:
{
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"sourceMap": true,
"target": "es5"
},
"compileOnSave": true
}
My gulp call is:
var ts = require('gulp-typescript');
...
var tsProject = ts.createProject("tsconfig.json");
...
gulp.task("ts", function () {
return gulp.src(tsInputFiles)
.pipe(tsProject())
.js
.pipe(gulp.dest("wwwroot/js"));
});
Just drop the module loading in the beginning of your typescript file, if you do not want to load any modules?
file1.ts:
$(function () {
});
If you try to compile this, you'll get an error:
file1.ts(2,1): error TS2581: Cannot find name '$'. Do you need to
install type definitions for jQuery? Try `npm i #types/jquery` and
then add `jquery` to the types field in your tsconfig.
Run npm as told above (npm init first, if npm has not been initialized in the directory).
Then add typeRoots and types to tsconfig:
{
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"sourceMap": true,
"target": "es5",
"typeRoots": [ "node_modules/types" ],
"types": [ "jquery" ]
},
"compileOnSave": true
}
After that, the compiling works, and you still have the strong typing in place (jquery types applied in compilation).
Browsers don't support JavaScript modules, so you'll need to tell the TypeScript compiler that you're trying to compile code that will be run on a browser. I don't know what the rest of your project looks like, but in your configuration, try adding "module": "es2015" or "module": "system" to your configuration, while also adding an outFile defining where you want to file to be generated :
in your tsconfig file :
{
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"sourceMap": true,
"target": "es5",
"module": "es2015",
"outFile": "script.js",
},
"compileOnSave": true
}
I wanted to use TypeScript files injected directly into a HTML file via gulp task (compiled into es5).
At first adding type="module" to <script> helped. But then more problems appeared, so finally I've end up using this notation instead of import:
/// <reference types="#types/jquery" />
/// <reference path="my_custom_file.ts" />
/// <reference path="my_externalTypes.d.ts" />
and namespace in each of the file to separate them from each other.
That should work for a simple, small projects.

Typescript outfile with System.JS - Module instantiation error

I'm using TypeScript to generate a single outFile that compiles my modules, loaded with SystemJS. When I follow the documentation on loading bundles, as suggested by this SO answer, I get an error:
Uncaught (in promise) Error: Module instantiation did not call an anonymous or correctly named System.register.
Instantiating http://localhost:50001/Content/js/app.js
Loading app.js
at vendor.js?v=c419d08…:4
Here is the setup script in my index.html file:
SystemJS.import("/Content/js/app.js").then(function (mod) {
return SystemJS.import("admin/js/startup");
});
app.js looks like this:
System.register("shared/js/utilities", [], function (exports_1, context_1) {
...
});
System.register("admin/js/startup", ["shared/js/utilities"], function (exports_2, context_2) {
...
});
My tsconfig.json, if it helps:
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5",
"module": "system",
"outFile": "app.js"
},
"compileOnSave": true,
"exclude": [
"node_modules",
"wwwroot"
]
}
UPDATE: I had been using systemjs/dist/system-production.js, because the documentation states that modules already transpiled into the System.register format, which is done by TypeScript, can be loaded by the production loader. If I switch to using systemjs/dist/system.js, I do not get the errors. I still don't see how I am getting this error from the production loader if I'm already working with System.register formatted modules.

Categories

Resources