Angular 5 Upgrade Build Issue, Uncaught ReferenceError: define is not defined - javascript

I just upgraded from Angular 4.3.3 to Angular 5.2.1. With doing so now when I build in dev (ng build --dev) the project build just fine. But when building in prod (ng build --prod) and the application loads in the console I get "Uncaught ReferenceError: define is not defined". I have verified that I have updated all the depreciated syntax in my project.
Does anyone else have any other ideas.
I am using a third party package called Wijmo, but I have already updated that to their latest stable release.

Please find the answer here:
The build started working for me after I replaced Wijmo AMD modules (from the NpmImages\wijmo-amd-min folder) with CommonJS modules (from the NpmImages\wijmo-commonjs-min folder).
This looks like not a problem with Wijmo AMD, the details below.
Below are the details of the investigation.
The problem is caused by the Build Optimizer process, controlled by the “--build-optimizer” flag, true by default for “—prod” builds with Angular 5 (false for Angular 4).
The build works without problems if to use non-minified Wijmo AMD modules from the NpmImages\wijmo-amd-src folder.
I checked the minified wijmo.js module and it’s absolutely correct (details below), which means that Build Optimizer just contains a bug that doesn’t allow it to correctly parse a minified AMD module.
Below are some details about how CollectionView class is exported from the wijmo.js module.
A. Non-minified wijmo.js:
A.1) Here’s the AMD ‘define’ function declaration:
define(["require", "exports", "wijmo/wijmo"], function (require, exports, wjcSelf) {
A.2) Here’s the beginning of the CollectionView class definition:
var CollectionView = (function () {
function CollectionView(sourceCollection, options) {
var _this = this;
this._idx = -1;
this._srtDsc = new ObservableArray();
this._grpDesc = new ObservableArray();
A.3) Here the CollectionView export statement:
exports.CollectionView = CollectionView;
Note that it uses ‘exports’ parameter passed to the ‘define’ callback function in #1 (bolded).
B. Now let’s check how this stuff looks in the minified wijmo.js module:B.1) AMD define:
define(["require","exports","wijmo/wijmo"],function(t,e,n)
Note that ‘exports’ parameter from A.1 is renamed to ‘e’.
B.2) Beginning of the CollectionView class definition:
Mt=function(){function t(t,e){var n=this;this._idx=-1,this._srtDsc=new xt,this._grpDesc=new xt,
“var CollectionView” from A.1 is renamed to Mt here.
B.3) Export statement
e.CollectionView=Mt;
‘e’ is the ‘e’ parameter from the ‘define’ callback function from B.1, which is a minified version of the ‘export’ parameter from A.1.
I.e. the minified wijmo.js module exports CollectionView absolutely correctly, and it seems that the problem is in the Build Optimizer. We can do nothing here.
So the workaround could be to use non-minified Wijmo AMD modules.
But as I said before – the right way is to use CommonJS format, this will save from problems like this!
~Manish

Related

How to compile a TypeScript project to a single JS file so it is usable in browser

I have to write a Javascript SDK for a little project I am working on. To do that, I had thought of creating a TypeScript project and compiling it to a single Javascript file, so the users of my SDK could just inject that file in their web pages.
However, I just came to know that if I use import, and try to compile to a single file, then it only supports SystemJS.
So, how to compile a TypeScript project to a single JS file so it is usable in browser?
By usable in browser, I mean that if I create a class App in TypeScript, then I could do this in dev console:
var x = new App();
I have been at this for more than a hour now, and everything I have found seems to suggest that this is not possible.
Edit: This doesn't really answer my question. Like I said in the example, I need the functionality that if there is a class called App in my TypeScript project, it should be visible to the browser with the same name, so I could do var x = new App() in my dev console. (Or a user can do this in his JS file that he injects after injecting my SDK file). That answer is just telling how to create an outfile in SystemJS.
For this you can use webpack, it is a Node.JS utility that attempts to bundle Node.JS-like modules. Webpack doesn't automatically export modules to the global object, but generates (or attempts to generate) a function that replace the Node.JS's default require, which is used to execute the entry module and others, thus you can modify this function for exporting each module (or properties of each module) in the global object.
(In TypeScript, use the CommonJS module. Second, install and use the ts-loader plugin among with webpack, so you'll directly compile TypeScript from webpack.)
Maybe that applies to Webpack 2. For example, you modify the __webpack_require__ function. It is not inside the global object and thus you must interfere in the webpack's generated source code, at function __webpack_require__:
function __webpack_require__(moduleId) {
// [...] (After the `if (installedModules...) ...`)
/*
* You don't have access to the module name, so export each
* property to the browser's global object.
*/
var exports = module.exports;
for (var key in exports)
window[key] = exports[key];
}

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

Require JS files dynamically on runtime using webpack

I am trying to port a library from grunt/requirejs to webpack and stumbled upon a problem, that might be a game-breaker for this endeavor.
The library I try to port has a function, that loads and evaluates multiple modules - based on their filenames that we get from a config file - into our app. The code looks like this (coffee):
loadModules = (arrayOfFilePaths) ->
new Promise (resolve) ->
require arrayOfFilePaths, (ms...) ->
for module in ms
module ModuleAPI
resolve()
The require here needs to be called on runtime and behave like it did with requireJS. Webpack seems to only care about what happens in the "build-process".
Is this something that webpack fundamentally doesn't care about? If so, can I still use requireJS with it? What is a good solution to load assets dynamically during runtime?
edit: loadModule can load modules, that are not present on the build-time of this library. They will be provided by the app, that implements my library.
So I found that my requirement to have some files loaded on runtime, that are only available on "app-compile-time" and not on "library-compile-time" is not easily possible with webpack.
I will change the mechanism, so that my library doesn't require the files anymore, but needs to be passed the required modules. Somewhat tells me, this is gonna be the better API anyways.
edit to clarify:
Basically, instead of:
// in my library
load = (path_to_file) ->
(require path_to_file).do_something()
// in my app (using the 'compiled' libary)
cool_library.load("file_that_exists_in_my_app")
I do this:
// in my library
load = (module) ->
module.do_something()
// in my app (using the 'compiled' libary)
module = require("file_that_exists_in_my_app")
cool_library.load(module)
The first code worked in require.js but not in webpack.
In hindsight i feel its pretty wrong to have a 3rd-party-library load files at runtime anyway.
There is concept named context (http://webpack.github.io/docs/context.html), it allows to make dynamic requires.
Also there is a possibility to define code split points: http://webpack.github.io/docs/code-splitting.html
function loadInContext(filename) {
return new Promise(function(resolve){
require(['./'+filename], resolve);
})
}
function loadModules(namesInContext){
return Promise.all(namesInContext.map(loadInContext));
}
And use it like following:
loadModules(arrayOfFiles).then(function(){
modules.forEach(function(module){
module(moduleAPI);
})
});
But likely it is not what you need - you will have a lot of chunks instead of one bundle with all required modules, and likely it would not be optimal..
It is better to define module requires in you config file, and include it to your build:
// modulesConfig.js
module.exports = [
require(...),
....
]
// run.js
require('modulesConfig').forEach(function(module){
module(moduleAPI);
})
You can also try using a library such as this: https://github.com/Venryx/webpack-runtime-require
Disclaimer: I'm its developer. I wrote it because I was also frustrated with the inability to freely access module contents at runtime. (in my case, for testing from the console)

angularjs undefined main module when minifying using typescript

I am trying to minify and uglify my angularjs + typescript app using grunt-minified. Currently I am getting an error that my main module for the app is not available when I minify. I know why this is occuring due variable names no longer matching the names of the modules they reference. How would I set up annotation so angular is able to identify my main module after minification?
declare module BB {
}
module BB.MyModule {
// initialize the module
export var module = angular
// load the dependencies
.module("MyModule", [
// dependancies
]);
}
This basic setup is working fine unminified, but MyModule is not defined when I minify it. How would I go about defining for safe minification?
You have:
declare module BB {
}
Probably BB has been minified to something else. That would make module BB.MyModule be different from BB.
Solution: Your code is already safe for minification if the point where you bootstrap angular https://docs.angularjs.org/api/ng/function/angular.bootstrap is minified through the same pipeline as BB.module is passed through.

Testing Custom Modules with DOH

I'm trying to build some unit tests for an old JS file/module that is out of my control.
The JS module is built using the following pattern...
var myModule = {
myMethod:function() {
}
};
I am then trying to build a DOH test harness to test this. I tried the following...
require([
"doh/runner",
"../../myModules/myModule.js"
], function(doh) {
console.log(doh);
console.log(myModule);
});
The file seems to be getting picked up fine but I can't reference anything in it. "console.log(myModule);" just returns undefined.
Anyone know how I can correctly include an external non dojo module JS file in a DOH test harness?
Thanks
Other than you shouldn’t be using DOH because it is deprecated (use Intern), there is no reason that you shouldn’t see myModule there. You are using a script address and not a module ID, which isn’t right, and you are using a relative path with a require call, which is also not right, but if either of these things were preventing the loader from finding and loading the script you are trying to load it should be throwing an error that you could see in the console. The only other possibility is you have somehow managed to build a built layer into this myModule script, in which case the entire script ends up wrapped in a closure and so using var foo will no longer define a global variable foo.
You need to declare myModule in the function callback to your require statement:
require([
"doh/runner",
"../../myModules/myModule"
], function(doh, myModule) { // <-- include myModule
console.log(doh);
console.log(myModule);
});
Just be sure that myModule.js returns your module.

Categories

Resources