I am trying to do a simple example using SystemJS Builder by building a SFX bundle, but I cannot get it to work. I cannot figure out how to call exported functions that were in the bundle. Am I missing something obvious?
index.html
<html>
<head>
<script src="app.bundle.js"></script>
<script>
all();
</script>
</head>
<body>
</body>
</html>
gulpfile.js
var path = require('path');
var gulp = require('gulp');
var Builder = require('systemjs-builder');
gulp.task('default', function(cb) {
var builder = new Builder('.', './jspm.config.js');
builder.buildStatic('src/app.js', 'dist/app.bundle.js').then(cb());
});
app.js
import { hello } from 'src/app/hello';
export function all() {
hello();
}
hello.js
export function hello() {
console.log("hello");
};
When I try to load index.html, it loads the app.bundle.js file correctly, but I can't seem to figure out how to call all() and I get Uncaught ReferenceError: all is not defined in Chrome.
The bundle file looks reasonable, I think:
// ... Some minified SystemJS content...
(["1"], [], function($__System) {
$__System.register("2", [], function (_export) {
"use strict";
_export("hello", hello);
function hello() {
console.log("hello");
}
return {
setters: [],
execute: function () {
;
}
};
});
$__System.register('1', ['2'], function (_export) {
'use strict';
var hello;
_export('all', all);
function all() {
hello();
}
return {
setters: [function (_) {
hello = _.hello;
}],
execute: function () {}
};
});
})
(function(factory) {
if (typeof define == 'function' && define.amd)
define([], factory);
else if (typeof module == 'object' && module.exports && typeof require == 'function')
module.exports = factory();
else
factory();
});
Exporting the all function does not mean it's accessible by the global object (window in the browser).
It just means that it can be imported using a module loaded (e.g. systemjs).
When creating a self-executing bundle you should just load the bundle file in the browser (as you already do) and do all bootstrapping also in the js files that are going to be in the bundle.
If you really need to access the all function in that script tag you must add the function to the global object.
in your app.js
window.all = all;
But i don't think this is the way its intended to be used.
Related
I am struggeling with the current situation. Up to today i had my own JavaScript implementation with own methods to load single js files per website - when needed. This way i had a tiny loader script with an scp sha256-checksum in the header which then loaded the "master" script which controlled everything else.
Now i want to go some steps further and a) switch over to modules, because most libs do so too, i was unable to load modules from normal scripts and b) implement typescript into my system.
What starts my script implementation:
/scripts/modules-loader.js
<html>
...
<script async type=module>
"use strict";
import {master} from '/scripts/modules/master-28021723540.js';
new master();
</script>
...
</html>
So far so good. This loader executes as expected, the js file is been loaded and the sha-256 hash from the header is valid.
And now where the struggle begins. This file is been compiled to
/master.ts
export class master {
constructor() {
this.init();
}
async init() {
console.log( "Hello, lets get started...");
}
}
compiled file:
define("wkwussmxlyk4d7ainbsq93pnpnugjs5g", ["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.master = void 0;
class master {
constructor() {
this.init();
}
async init() {
console.log("Hello, lets get started...");
}
}
exports.master = master;
});
with the result that the browser cannot find the module called "master"
Uncaught SyntaxError: The requested module '/scripts/modules/master-28021723540.js'
does not provide an export named 'master' (at (Index):11:9)
However i also tried this, which i found in the internet:
"use strict";
module master {
class master {
constructor() {
this.init();
}
async init() {
console.log( "Hello, lets get started...");
}
}
}
which gets compiled into this
"use strict";
var master;
(function (master_1) {
class master {
constructor() {
this.init();
}
async init() {
console.log("Hello, lets get started...");
}
}
})(master || (master = {}));
which leads to the same result.
How can i get my class get compiled from ts to be able to call it from the loader or in the file itself?
Just for understanding, i dont want to use the "tsc --watch" over my entire project. I am using single js/ts files and compile/optimize them in the request thread and put them into static optimized files afterwards ( if in production ). Keeping this in mind i am also open into different implementations. I am aiming for maximum pagespeed without compromises and my current solution was working very good but just limited because it was unable to load modules, so now i want to switch over to modules only.
i am compiling like this
/usr/bin/tsc --alwaysStrict --strict --module amd --target es2020 /srv/http/domain.local/tmp/domain.local/ncumh5cnk5uq2s7b64oa31cv19agr2s9.ts --outfile /srv/http/domain.local/tmp/domain.local/compiled-ncumh5cnk5uq2s7b64oa31cv19agr2s9.ts
Thanks in advance
Response on answer from #Quentin
/usr/bin/tsc --alwaysStrict --strict --target es6 /srv/http/domain.local/tmp/domain.local/ncumh5cnk5uq2s7b64oa31cv19agr2s9.ts --outfile /srv/http/domain.local/tmp/domain.local/compiled-ncumh5cnk5uq2s7b64oa31cv19agr2s9.ts
i am getting this compilation
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
class master {
constructor() {
this.init();
}
init() {
return __awaiter(this, void 0, void 0, function* () {
console.log("Hello, lets get started...");
});
}
}
and with
export class()
i am getting this:
Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.
--module amd
This is your problem.
AMD modules use the define syntax and do no have native support in browsers. To use them you’ll need to use something like Require.JS.
Instead, tell TypeScript to generate an es6 module.
I'm working to create a shared package of JavaScript functions. At this time, I'm trying to use them like this:
/app/index.js
const myPackage = require('../myPackage');
myPackage.function1();
myPackage.myScope.function2();
The above successfully loads myPackage. However, when I attempt to run function1, I receive an error that says: "TypeError: myPackage.function1 is not a function". My code in the "package" is organized like this:
/myPackage
index.js
root
function1.js
myScope
function2.js
The code looks like this:
index.js
require('./root/function1.js');
require('./myScope/function2.js');
function1.js
exports.function1 = function() {
console.log("Doing stuff in function1");
}
function2.js
exports.function2 = function() {
console.log("Doing stuff for function2");
}
I could understand function2 not working because, there's nothing putting it in myScope, which I don't know how to do. However, I don't understand why function1 isn't running. What am I doing wrong?
To elaborate bergi's answer, you need to have the following in your index.js file:
// file: index.js
exports.function1 = require('./root/function1.js').function1;
exports.myScope2 = {
function2: require('./myScope/function2.js').function2,
};
Because require('./root/function1.js') == exports object in function1.js. So if you
have multiple functions in your function1.js, you have to go like this:
// file: index.js
exports.function1 = require('./root/function1.js').function1;
exports.function11 = require('./root/function1.js').function11;
exports.function111 = require('./root/function1.js').function111;
...
A shortcut of that can be:
// file: index.js
Object.assign(exports, require('./root/function1.js'));
On the other hand: you can set the exports object to be your function:
// file: function1.js
module.exports = function() {
console.log("Doing stuff in function1");
}
Then you can have the following in your index.js file:
// file: index.js
exports.function1 = require('./root/function1.js');
exports.myScope2 = {
function2: require('./myScope/function2.js'),
};
Here require('./root/function1.js') == function1 from function1.js. Hope that explains
the issue.
Your index.js doesn't export anything. You will have to do
Object.assign(exports, require('./root/function1.js'));
exports.myScope = require('./myScope/function2.js');
Or maybe better have your function1.js and function2.js modules export the function itself (module.exports = function() { … };) instead of creating a property, then use
exports.function1 = require('./root/function1.js');
exports.myScope = {
function2: require('./myScope/function2.js'),
};
Anyone knows how to make a class or function on Typescript that executes its self on document ready?
I have a view, loaded with ajax, and I want to init some components on document ready without using javascript directly.
The Typescript is beeing transpiled to javascript with AMD.
So, if I use imports or exports, all the code is surrounded by a function call.
For example:
Typescript:
import Module from 'module';
class initTest {
public constructor() {
//init something here
}
}
let test = new initTest();
Javascript generated:
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var initTest = /** #class */ (function () {
function initTest() {
//init something here
}
return initTest;
}());
var test = new initTest();
});
//# sourceMappingURL=test.js.map
I have the following TypeScript class in the file: bar.ts
export class Bar {
log(message:string):void {
console.log(message);
}
}
In the file foo.ts I have:
import { Bar } from "bar";
window.onload = () => {
var foo = new Bar();
foo.log("Hello World");
};
I am compiling with:
lib: ["dom", "es2015.promise", "es2015"]
module: "amd"
declarationFiles: true
target: "ES5"
noImplicitAny: true
out: "test.js
How can I instantiate the Bar class? The window.onload event is not called. The following is the generated code:
define("bar", ["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Bar = (function () {
function Bar() {
}
Bar.prototype.log = function (message) {
console.log(message);
};
return Bar;
}());
exports.Bar = Bar;
});
define("foo", ["require", "exports", "bar"], function (require, exports, bar_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
window.onload = function () {
var foo = new bar_1.Bar();
foo.log("Hello World");
};
});
Is there a way to reference Bar from standard JavaScript? I have included require.js in the HTML page and there are no JavaScript errors when the page loads.
This is a simplified version of the problem but I need to use export as the project has many classes each stored in separate files and I need to combine them into a single file.
You should be able to reference Bar from regular javascript. Try to do it from the requirejs data-main script.
In the HTML:
<script data-main="scripts/main" src="scripts/require.js"></script>
In scripts/main:
requirejs(["bar"], function(bar) {});
I've got one file (app.js) with two named modules in it ("foo", and "bar" - where "bar" depends on "foo").
Question: How to I load "bar" it in the browser?
Disclaimer: I'm new to SystemJS and the docs look a little intimidating.
app.js
System.register("foo", [], function(exports_1) {
"use strict";
var App;
return {
setters:[],
execute: function() {
App = (function () {
function App() {
this.bar = 'Hello world.';
console.log(this.bar);
}
return App;
})();
exports_1("App", App);
;
}
}
});
System.register("bar", ["foo"], function(exports_1) {
"use strict";
var App;
return {
setters:[],
execute: function() {
App = (function () {
function App() {
this.bar = 'Mony a mickle maks a muckle.';
console.log(this.bar);
}
return App;
})();
exports_1("App", App);
;
}
}
});
Got the results I wanted by doing the following:
Added the <script src="app.js"> tag to my index file.
Also added System.import('bar'); to the page.
I wonder if this is the standard/recommended way of doing it.
Edit:
The issue with this approach is that I need two strategies for development and production.
In development I don't add the <script> tag and I import the module using System.import('path/app.js');
I think using a bare bones seed can help you out by showing a simple working example, this seed has a PRODUCTION and DEV MODE and you dont need to have 2 strategies, just choose between running it bundled or not
try:
npm i -g slush-jspm-react-seed