How to keep Grunt dom_munger from stripping your CDN dependencies? - angularjs

I have an object, Plaid, that is provided by a drop-in module from Plaid, called Plaid Link. Locally, the code works perfectly in my AngularJS front-end.
The module is loaded via my AngularJS app's index.html file, right next to all of the other script tags loaded for my application.
Index.html
<script src="https://cdn.plaid.com/link/stable/link-initialize.js"></script>
Here is the code where Plaid is called: (from an AngularJS controller)
$scope.addAccount = function(bankChosen) {
$log.debug("Plaid object: ", Plaid);
var linkHandler = Plaid.create({ // the troublesome line
env: 'tartan',
clientName: 'Example Project',
key: 'test_key',
product: 'connect',
onSuccess: function(public_token) {
Restangular.one('plaid').customPOST(
{
public_token: public_token,
user_id: $scope.currentUser.id,
institution_code: bankChosen
},
'addAccount'
);
},
onExit: function() {
$state.go('dashboard.successState');
},
});
linkHandler.open(bankChosen);
};
However, when I push to the production environment, currently hosted on Heroku, it gives the javascript error ReferenceError: Plaid is not defined when it tries to load. It is breaking error when deployed to production.
What could be causing this module to be unavailable during production?
The script that loads the CDN could be getting stripped away by a standard grunt task that does that sort of thing? Or maybe I am supposed to be loading the module from the CDN in some other way in a production-environment setting? I really don't know...
Update: I found one thing that might be stripping the loaded module
From the Grunt dom-munger docs
Use this task to read and transform your HTML documents. Typical use cases include:
Read the references from your script or link tags and pass those to
concat,uglify, etc automatically.
2. Update HTML to remove script
references or anything that is not intended for your production
builds.
Add, update, or remove any DOM elements for any reason.
dom_munger is part of my application's build process, which happens when it is deployed (!). Grunt is the likely culprit here.
Does anybody know how to load the script tag above, with dom_munger as still part of my app's grunt build step?

The problem was that during the build step Grunt strips away the script tags in my application. So I had to append the tag back on to my body tag using dom_munger's update --> options --> append option.
...only then could I get the CDN script to be linked to properly after the app was built using grunt build.
The line looks like this in my Gruntfile.
--> The key added line is this one
{selector:'body',html:'<script src="https://cdn.plaid.com/link/stable/link-initialize.js"></script>'},
dom_munger:{
[.....]
update: {
options: {
append: [
{selector:'body',html:'<script src="https://cdn.plaid.com/link/stable/link-initialize.js"></script>'},
]
},
src:'index.html',
dest: 'dist/index.html'
}
Quite the mysterious error for me. I hope this helps somebody else out at some point!

Related

angularjs-route not loading with angular --prod flag (angular-cli)

Context: I'm migrating from ngJs to ng10, the application runs normally when I not use the --prod flag
The thing is: when i use --prod flag the routes doesn't load and i am super clueless why not.
The only difference I see printing the "next" attribute on the $routeChangeStart is that the "next" object on --prod mode doesnt have an attribute called "locals"
2nd. weird thing: the $routeChangeStart is triggered when i change the URL on the URL bar as it should be, cus the $routeChangeStart is printed every time i change the URL
3rd. weird thing: for testing purposes i change templateUrl in the config for a template:'<div>Arcade PvP silly text</div>' and it doesnt load either, and as far i see, the controller of any view never triggers.
Pls help.
Angular-CLI 10.0.5
Angular 1.7.6 bootstraped over Angular 10.0.6
Okay, I manage to understand more deeply the reasons of this behavior and manage to make a workaround, gonna documentate it here:
This is an application made in AngularJS (1.7.x) bootstrapped over Angular 10.0.5
Deploying the application with ng serve --configuration=dev makes it work as expected after the normal long process of configure the different index.ts and convert everything from *.js to *.ts
The reason of the issue is located in the angular.json:
{
"projects":{
[project_name]:{
"architect":{
"build":{
"configurations":{
"production":{
...
"optimization":true <------- THIS
}
...
}}}}}}
The optimization flag effectively makes the bundle very lightweight and ng build --prod compiles normally. But as I mention in the question, the problem occurs at runtime: the routes "load" but the HTML never renders for any route configured, therefore ANY of the controllers either runs.
In deep investigation, the optimization flag tells the angular-cli webpack to run the minification over the JS, and by past experience, AngularJS seems to be tricky to receive the minifications/uglify processing all due to the mangle process, my problem is one of the reasons why.
Angular-CLI's Webpack runs TerserPlugin to make the minification and I need to configurate it to avoid using mangle, Angular now allows to use a custom webpack configuration file to add rules, this is achieved like this:
create a new file in the project base folder, let's say named custom-webpack.config.js
Reference this file in the angular.json build:
{
"projects":{
[project_name]:{
"architect":{
"build":{
"builder":"#angular-builders/custom-webpack:browser",
"options":{
"customWebpackConfig": {
"path": "./custom-webpack.config.js"
},
...
}
}}}}}}
In the file, let's do this:
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: true,
terserOptions: {
mangle: false,
ie8:false,
safari10:false
}
}),
],
}
}
And voila! The minification occurs, but not the mangle, the application will reduce it's bundle size as expected (mostly) and the angular-route will work normally.

Integrate Babel into Angular 1.5

I have built an angular website working perfectly fine in chrome, but it is failing in IE because of ES6
I am running angular using cdn with a node server which is only used for serving the webpage, no code is there other than listening to port.
I want to add babel into that, but all the examples I am finding are for server code or using gulp or webpack. Is there any way to directly integrate babel for my purpose or I definitely need to have webpack\gulp configured.
Included the directory structure of the code, all the files are getting linked in index.html
Since babel changes your javascript I don't think you can include it in your html page you need to have it in a grunt or such pipeline so the javascript is transformed and then the transformed javascript is served:
gulp.task('build', [], function () {
return gulp.src('./app/index.html')
.pipe(preprocess({context: production_config.context}))
.pipe(babel({ presets: ['env'] }))
.pipe(gulp.dest('./build');
});
Then serve "build" instead of "app"
Maybe there's a more dynamic way

creating a ydn-db service for angularjs

I'm working on a project using Meanjs and ydn-db for indexeddb support.
So I'm trying to make a service in angular, but I just can't figure a way to include the js file properly. I've tried installing the lib in the following methods:
bower install ydn-db
bower install ydndb
The first case, I could not find a suitable.js file like ydn.db-isw-core-qry-dev.js. Now the second would install the two minified versions which I could work, but I always get the ydn not found error
Now by looking into the Developer's page http://dev.yathit.com/ydn-db/getting-started.html I can see that he has a way of making the require in the AMD loader section, which I simply did not know how to use inside the service factory.
Here is what I'm trying to do inside the factory which by the way I don't think is best practices...
And these are the error that I'm getting just by trying to load this...
How can I use this lib while still following best practices for angular or at least just to get it working without errors?
ldb undefined
Object {db: Object, debug: Object}
Uncaught ydn.error.ArgumentException: Unknown attribute "keypath"
angular.module(ApplicationConfiguration.applicationModuleName).factory('Localdb',['$resource','$q',
function($resource,$q) {
var deferred=$q.defer();
require.config({
baseUrl: '/content',
paths: {
ydn: 'scripts/ydn.db-isw-core-qry-dev'
}
});
require(['scripts/ydn.db-isw-core-qry-dev'], function(ldb){
console.log ('ldb',ldb);//this is undefined
var schema ={
stores:[
{
name:'process',
keypath:'_id',
indexes:[{
name:'processId',
keypath:'processId',
unique:false
},{
name:'processMeta',
keypath:'processMeta',
unique:false
}
]
}
]
};
console.log(ydn);//this gets back ok but then the keypath error???
deferred.resolve(new ydn.db.Storage('pdc',schema));
});
return deferred.promise;
}
]);
Sorry, to get your trouble. ydn-db repo do not have compiled js file, as require (I think) by bower. So it doesn't work. Just download one of the js file and add to your html.
Also check out ydn-db with angular example app.

Sails.js + RequireJS configuration

Having all kinds of problems getting Sails to work with RequireJS, mainly because I can't find any definitive source on the best way to do this. There are several posts out there that discuss this, but they are older and all do things differently. Would really love to see the Creators enlighten the community on the proper way to do this given the changes to the Sails application structure, linker process etc. in the latter versions (.0.9.9, ,0.10)
So, first question would be...if I am planning on using an AMD/RequireJS + Backbone approach for my client-side code, and want to use the R.js Optimizer in grunt to build my production JS file and resolve all the nested dependencies automatically (rather than have to list them out manually), should I not create the application with the --linker option and manually manage the grunt build process myself?
Also, where in the directory structure should the "vendor" directory be placed that contains all the dependent JS libs like Underscore, jQuery, Backbone etc. reside?
I decided this problem:
Install the plugin for grunt-requirejs
wrote config to run build in a folder /tasks/config/requirejs.js
Example:
module.exports = function(grunt) {
grunt.config.set('requirejs', {
dev: {
options: {
baseUrl: "assets/",
name: 'main',
optimize: "uglify2",//'none',//"uglify2",
//wrap: true,
paths: {
// Major libraries
jquery: '../vendor/jquery',
underscore: '../vendor/underscore',
backbone: '../vendor/backbone',
// Require.js plugins
},
removeCombined: true,
inlineText: true,
useStrict: true,
out: "build/main.js",
waitSeconds: 200
},
}
});
grunt.loadNpmTasks('grunt-contrib-requirejs');
};
added to autostart in tasks/register/compileAssets.js
Example:
module.exports = function (grunt) {
grunt.registerTask('compileAssets', [
'clean:dev',
'jst:dev',
'less:dev',
'copy:dev',
'coffee:dev',
'requirejs:dev'
]);
};
You also have to adjust just grunt at yourself and do not be afraid to change anything. At design time, better to store scripts in the Assets folder because it is convenient.
For others having the same problem, a quick but only partial fix is to disable the script injection by removing the following from layout.ejs:
<!-- SCRIPTS -->
<!-- SCRIPTS END -->
Then just place direct links to your require.js file:
<script src="/linker/js/components/requirejs/require.js"></script>
I say this is only a partial fix because the GruntFile will need need to implement a require task in order to concatenate the files correctly.

Backbone.Marionette - Grunt Browserify - "require is not defined"

I'm using grunt-browserify and running into two issues in particular. The task is up and running successfully with the following config options. The variable jsFilesToConcat represents all of the javascript files for a Backbone.js + Marionette.js application, the main application defintion, the front-end utility assets (e.g. Bootstrap plugins), and all JS associated with the project. Is this the wrong approach? The thought was to load the entire 250k JS application (and all it's dependencies) at one time.
I want to offer the disclaimer that this is new territory for me, so I think my intended use case is available with the options already available with the plugin, but I'm confused by two errors:
1) Backbone not defined - which means that the script is in fact loading, however, when I inspect the call stack in Chrome Dev Tools it shows only the anonymous self-invoking function. So I'm not clear on how to pass the Backbone object to Marionette in order for it to be extended at load time.
2) require is not defined - error on the line where I'm declaring var SampleApp = require('SampleApp'). Do I need to do something special within my grunt config, or node.js server.js config to expose the require function?
3) Is the javascript executing asynchronously within itself, is this part of the browserify intended behavior that I'm not properly handling? I think since I'm wrapping alot of JS utilities in a global wrapper to protect namespacing, that's the reason some functions are not available, but I'm not clear on why that would affect require.
// uses grunt-browserify task
browserify: {
developmentJs: {
options: {
debug: true,
alias: ["./js/app.dev.js:SampleApp"],
},
src: [
'<%= pkg.jsFilesToConcat %>'
],
dest: 'public-dev/js/app.dev.js'
}
}
and then in the index.html of my single-page Marionette app, I have.
(function ($) {
$(document).ready( function() {
var sampleApp = require('SampleApp');
console.log( SampleApp );
});
})(jQuery);
Well for starters, the src attribute in your grunt file doesn't need to reference all of the files in your application. It only needs an entry point. So normally I have something similar to your anonymous self executing function in an index.js file, and set my src configuration option to ["./index.js"]. When browserify looks at that file, it will check for calls to require and grab all of the required dependencies.
That said, browserify will generate a file with an internal definition of require. The require function is not globally available on the page, nor are the dependencies that you include with require. You can use them in your application, but that doesn't make them available in the page. So if you are getting a Backbone is not defined error, the first thing I would check is that you have installed backbone via npm (npm install backbone --save).
Once everything is set up you should just have to include your compiled script on the page, and let your anonymous self executing function (which should now be in a file that grunt-browserify is processing) do the work to kick off your application.

Resources