Compiling into CommonJS does not produce files usable by NodeJS - javascript

Given the syntax provided here (standard ES6 modules with import/export), and the files below, the typescript compiler (tsc) builds files which will throw Error: Cannot find module when used with NodeJS.
Here's a stripped down example:
Input files
src/main.ts
import {Example} from 'example';
let e = new Example();
src/example.ts
export class Example {}
Compilation
Note, using the tsc from npm install -g typescript, version 1.5.0-beta, from a windows machine.
tsc --rootDir src --outDir bin
Output files
bin/main.js
var example_1 = require('example');
var e = new example_1.Example();
bin/example.js
var Example = (function () {
function Example() {
}
return Example;
})();
exports.Example = Example;
Am I doing something incorrectly? I expected main.js to include something like require('example.js') instead.

import {Example} from 'example';
You're importing a module here, not a file. Try
import {Example} from './example';

Related

Javascript modules - Cannot use import statement outside a module

I am new to Javascript and I am trying to learn modules from a tutorial. In have a folder in visual studio code/VScode which has two files, script.js & external.js.
Script.js imports content from external.js and prints text to console. I get the below error when I run script.js from vs code, with node.js run configuration. Can someone please tell me why this happens and how to fix it ? In comparison, imports in Java are simple.
import {keyValue} from './external.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:1070:16)
at Module._compile (internal/modules/cjs/loader.js:1120:27)
external.js :
export let keyValue = 1000;
script.js :
import {keyValue} from './external.js';
console.log(keyValue);
UPDATES :
Node version - v12.16.2, upgraded to v14.4.0.
What's the version of node.js?
If node.js is version 13 or above, you can do either:
add { type: "module" } to package.json.
{
...
scripts: "...",
type: "module"
}
rename .js to .mjs
If it's under 13, rename .js to .mjs, and run with additional params --experimental-modules.
node --experimental-modules script.js
Or
You can also fix the import statement outside a module issue
by not using the import statement and using the dynamic import function instead.
script.js
import("./external.js").then((module) => {
console.log(module.keyValue);
});
This form also supports the await keyword.
let module = await import('./external.js');
console.log(module.keyValue)
it's because you are using es6 modules instead of the default module system for node which is common js. you could either use babel to transpile it or to use the .mjs extension

Browserify does not work - why?

I have the following code that I browserify to bundle.js, that I include (before loading any other .js file) on my front-end. The file I browserify is simply this this:
var firebase = require('firebase')
I then call authorize() on this variable, in the next file that is included on the front-end, but I get an error saying firebase is not defined?
Browserify is a module bundler that enables you to use CommonJS (Node) modules in your browser. This implies that your project must follow CommonJS conventions to export (exports, module.exports) and import (require) modules. Here is a basic example:
Your module (module.js)
var foo = function () {
console.log('Foo');
};
var bar = function () {
console.log('Bar');
};
module.exports = {
foo: foo,
bar: bar
};
Your entry point (main.js)
var module = require('./module');
module.foo(); // Foo
module.bar(); // Bar
This code will work out-of-the-box with Node, but your browser cannot interpret it. This is where Browserify is useful...
When you run the command browserify main.js -o bundle.js on your entry point, Browserify traverses all your dependencies (here module.js) and loads them in a bundle. This bundle is usable in your browser, so you can now load it in a script tag:
<script src="bundle.js"></script>

How to tell which files are being transpiled by Babel 6?

I have a project that is using babel-register to dynamically transpile ES6 source to ES5 when requiring that module in a Node 6.6 project. I've read that babel-register hooks into Node's require function in order to transpile a file when you try to load it, but I'm not always clear on which files will be affected by that change.
This question comes up for me a lot when I'm writing tests: is only my production code getting transpiled, or does the test code get transpiled too?This brings me to the more general question, which is the topic of this post:
How can I tell when Babel is actually running, and which files are being transpiled?
Example code
Let's say I have production classes like this that are written in ES6 syntax
//src/greeter.js
export default class Greeter {
sayHello() {
return 'Hello World';
}
}
and Babel is configured to transpile as so (.babelrc)
{
"presets": ["es2015"]
}
and then there's some test code
//features/step_definitions/greeter_steps.js
import Greeter from '../../src/greeter'; //Causes greeter.js to be transpiled
import expect from 'expect';
var stepWrapper = function() {
//Does Babel try to transpile this code too?
this.Given(/^a greeter$/, function() {
this.greeter = new Greeter();
});
this.When(/^I ask it for a general greeting$/, function() {
this.greeting = this.greeter.sayHello();
});
this.Then(/^it should greet the entire world$/, function() {
expect(this.greeting).toEqual('Hello World');
});
};
module.exports = stepWrapper;
and all of that runs on Node like so
cucumberjs --compiler js:babel-core/register
Example code is available here, if that is helpful.
I made a hack to node_modules/babel-register/lib/node.js to do some logging like so
function compile(filename) {
var result = void 0;
var opts = new _babelCore.OptionManager().init((0, _extend2.default)({ sourceRoot: _path2.default.dirname(filename) }, (0, _cloneDeep2.default)(transformOpts), { filename: filename }));
var cacheKey = (0, _stringify2.default)(opts) + ":" + babel.version;
var env = process.env.BABEL_ENV || process.env.NODE_ENV;
console.log('[babel-register::compile] filename=' + filename + '\n'); //Added logging here
if (env) cacheKey += ":" + env;
if (cache) {
var cached = cache[cacheKey];
if (cached && cached.mtime === mtime(filename)) {
result = cached;
}
}
...
}
which then reports that test and production code are at least passing through Babel on some level
$ npm t
> cucumber-js-babel#1.0.0 test /Users/krull/git/sandbox/node/cucumber-js-babel
> cucumberjs --compiler js:babel-core/register
[babel-register::compile] filename=.../node/cucumber-js-babel/features/step_definitions/greeter_steps.js
[babel-register::compile] filename=.../node/cucumber-js-babel/src/greeter.js
...test results...
However, I'm hoping for a better solution that
works by some means of plugins and/or configuration, instead of monkey patching
better distinguishes which files are actually being transpiled, and which ones pass through Babel without modification
Because of this:
cucumberjs --compiler js:babel-core/register
...babel is invoked for both your test and regular source code. Keep in mind that in node, the only way to import JS is through require, so obviously babel-register will always be invoked. Of course, what babel does depends on its configuration, but most likely you have a simple configuration where all files required by require except those under node_modules will be transpiled.

Typescript module, require external node_modules

I need to use a simple node_module inside a simple typescript file, but it seems that the compiler doesn't want to get it.
Here's my simple ts file :
import glob = require('glob');
console.log(glob);
And I've got this error :
[13:51:11] Compiling TypeScript files using tsc version 1.5.0
[13:51:12] [tsc] > F:/SkeletonProject/boot/ts/Boot.ts(4,23): error TS2307: Cannot find external module 'glob'.
[13:51:12] Failed to compile TypeScript: Error: tsc command has exited with code:2
events.js:72
throw er; // Unhandled 'error' event
^
Error: Failed to compile: tsc command has exited with code:2
npm ERR! skeleton-typescript-name#0.0.1 start: `node compile && node ./boot/js/Boot.js`
npm ERR! Exit status 8
npm ERR!
npm ERR! Failed at the skeleton-typescript-name#0.0.1 start script.
However, when I use a simple declaration in this same script, it works :
var x = 0;
console.log(x); // prints 0 after typescript compilation
What am I doing wrong in this case ?
EDIT:
Here's my gulp file :
var gulp = require('gulp');
var typescript = require('gulp-tsc');
gulp.task('compileApp', ['compileBoot'], function () {
return gulp.src(['app/src/**/*.ts'])
.pipe(typescript())
.pipe(gulp.dest('app/dist/'))
});
gulp.task('compileBoot', function () {
return gulp.src(['boot/ts/*.ts'])
.pipe(typescript({
module:'commonjs'
}))
.pipe(gulp.dest('boot/js/'))
});
gulp.start('compileApp');
Thanks for advance
Thanks for advance
You are using the correct syntax:
import glob = require('glob');
But the error: Cannot find external module 'glob' is pointing out that you are using a special case.
By default, the compiler is looking for glob.ts, but in your case you are using a node module, not a module that you have written. For this reason, the glob module will need special treatment...
If glob is a plain JavaScript module, you can add a file named glob.d.ts with type information that described the module.
glob.d.ts
declare module "glob" {
export class Example {
doIt(): string;
}
}
app.ts
import glob = require('glob');
var x = new glob.Example();
Some Node modules already include the .d.ts in the package, in other cases you can grab it from Definitely Typed.
Here is the error with your code
import glob = require('glob');
Because in node.js import is not a reserved keyword. If you require any module in your application, you simply require it using the statement
var glob = require('glob');
Once done you can then use
console.log(glob);
To print the value of glob.Replacing import will hopefully do the job for you.

How can I use tsc to generate amd modules from typescript?

I am attempting to use the command-line program tsc to compile my .ts file into an amd module.
Here's the example file test.ts:
module Test {
var x = 1;
}
This is the command I use to generate the output:
tsc --module amd test.ts --out test.js
Here is my generated test.js
var Test;
(function (Test) {
var x = 1;
})(Test || (Test = {}));
I was expecting to see a first line that referenced require and define, something like:
define(["require", "exports"], function(require, exports) {
Any clue as to why this output is not as it seems like it should be? If I remove the module amd from the command I get the exact same output for my test.js file.
This is my version of tsc:
$ tsc --version
Version 0.9.1.1
Check the TypeScript language spec (quite readable, btw) on the difference between external and internal modules.
$ cat module.ts
export var x = 1;
$ tsc --module amd module.ts
$ cat module.js
define(["require", "exports"], function(require, exports) {
exports.x = 1;
});

Categories

Resources