I have a problem with upgrade my angularJs Application to Webpack4.
this is my setup:
vendor.ts
import "angular";
import "angular-i18n/de-de";
import "angular-route";
and
main.ts
import {MyAppModule} from "./my-app.app";
angular.element(document).ready(() => {
angular.bootstrap(document.body, [MyAppModule.name], { strictDi: true });
});
With webpack 3. I had a commonsChunkPlugin and everything worked.
With webpack 4, I'm using the splitChunks option to not import angularjs 5 times:
webpack.config.ts
...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 2
}
}
}
}
...
That is working correctly. I have loaded the angularjs code only in my common.js file. But unfortunatelly the code is instantiated twice, so the app always logs the warning:
WARNING: Tried to load AngularJS more than once.
The chunks are loaded via HtmlWebpackPlugin in the html.
Any idea how to remove the warning?
Found the solution in the deeps of github issues:
The vendor file should not be an entry point but the entry point should be a list of files:
...
entry: {
main: ['./vendor.js', './main.js']
},
...
Related
I haven't found anything related to this topic.
I'd like to import pusher like normally is done with other js frameoworks:
npm install pusher-js
Then you just import the library:
import Pusher from 'pusher-js';
or
const Pusher = require('pusher-js');
Please share good practices to accomplish that in an ExtJS application.
The last resort would be to just include the min file in app.json:
...
"js": [
{
"path": "https://js.pusher.com/7.0/pusher.min.js",
"bundle": true,
"compress": false
}
], ...
Or even worse, put the include in the index.html file:
<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
Any ideas?
Thanks.
if including it using app.json is not what you want you can load it at the time you need it.
Async (onLoad, onError are the promise)
Ext.Loader.loadScript({
url: 'pusher-js',
onLoad: successFn,
onError: errorFn,
scope: this
});
Sync (the code will continue, after the file has been loaded)
Ext.Loader.loadScriptsSync(url|[url]);
Optional Approach
If you add Ext.require ExtJS will try to load the file and you can use this in your controller.
Ext.define('MyApp.view.SomeViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.someview',
init() {
// Preload additional functionality
Ext.require('MyApp.libs.pusher-js');
// from folder ===> MyApp/app/libs/pusher-js
}
})
OR
Read this as a starting point.
Using app.json you can get it all prepared as:
"js": [
{
"path": "https://js.pusher.com/7.0/pusher.min.js",
"remote": true
}
],
...
Inside your initialization:
var pusher = new Pusher('APP_KEY', {
cluster: 'APP_CLUSTER'
});
This will load the file automatically and you do not have to import it in any way.
I'm working on preparing a .net based AngularJS web application for modern tooling(get rid of nuget in favor of npm, bundling with webpack, etc.) and later on re-writing it to Angular.
I'm having an issue with the bundled version where a directive is trying to bind a click events to a template anchor tag (< a >) but the template is not yet loaded.
On the old version with many < script > tags for every JS file this is not happening. The directive is first on the order and the controller of the template(which is loaded inside a ng-include and uses the directive) comes after.
On the bundled version I simply changed the .js files to .ts, added the npm dependencies, the needed imports statements on each file and in the webpack entry I kept the same order as in the old index.html. Still, when de directive code runs the elements it searches for are not there yet.
The parts affected: (already updated with #bryan60 answer suggestion)
shell.html
...
<div data-ng-if="vm.showMenuBar" data-ng-include="'/app/layout/sidebar.html'" class="fader-animation"></div>
...
shell.ts
import angular from 'angular';
const sideBarTemplate = require('./sidebar.html')
let controllerId = "shell";
angular.module("eqc").controller(controllerId, ["$rootScope", "$templateCache", "$window", "authService", "common", "config", shell]);
function shell($rootScope, $templateCache, $window, authService, common, config) {
$templateCache.put('app/layout/sidebar.html', sideBarTemplate)
sidebar.html
<div data-cc-sidebar data-ng-controller="sidebar as vm">
<div class="sidebar-filler"></div>
<div class="sidebar-dropdown">Menu</div>
<div class="sidebar-inner">
<div class="sidebar-widget"></div>
<ul class="navi">
<li class="nlightblue fade-selection-animation" data-ng-class="vm.isCurrent(r)" data-ng-repeat="r in vm.navRoutes">
</li>
</ul>
</div>
cc-sidebar directive:
app.directive('ccSidebar', function () {
// Opens and clsoes the sidebar menu.
// Usage:
// <div data-cc-sidebar>
// Creates:
// <div data-cc-sidebar class="sidebar">
var directive = {
link: link,
restrict: 'A'
};
return directive;
function link(scope, element, attrs) {
var $sidebarInner = element.find('.sidebar-inner');
var $dropdownElement = element.find('.sidebar-dropdown a');
element.addClass('sidebar');
$dropdownElement.click(dropdown); // <--- Here's the problem. 'dropdown' function is omitted but its defined in the next line
// The error on the console is: TypeError: "$dropdownElement.click is not a function"
// That's because it is never found
main.ts
import "./eqc";
import "./config"
import "./config.exceptionHandler"
import "./config.route"
//All folders bellow have index.ts in them including their .ts files
import "./common"
import "./services"
import "./Views"
import "./layout"
eqc.ts
import 'jquery';
import angular from 'angular';
import 'angular-animate';
import 'angular-route';
import 'angular-sanitize';
import 'angular-messages';
import 'angular-local-storage'
import 'angular-ui-bootstrap';
import 'angular-ui-mask';
import 'angular-loading-bar';
import 'breeze-client';
import 'breeze-client/breeze.bridge.angular';
let eqc = angular.module("eqc", [ .....
webpack.config.ts
const path = require('path');
module.exports = {
mode: "development",
entry: "./src/app/main.ts",
output: {
path: path.resolve(__dirname, "src/dist"),
filename: "bundle.js"
},
module: {
rules: [
//All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'
{
test: /\.tsx?$/,
use: { loader: "ts-loader" }
},
{
test: /\.html$/,
use: { loader: 'html-loader' }
}
]
},
resolve: {
//Add '.ts' and '.tsx' as a resovaable extension
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
},
devtool: "source-map"
};
My folder structure:
not sure exactly what your problem is due to the lack of code / details... but very generally, the simplest way to make ng-include work with webpack is to use require statements and the template cache....
Assuming you have some template like:
<ng-include src="'app/my-included-template.html'"></ng-include>
in the controller for that template, you'll have something set up like...
const myIncludedTemplate = require('./my-included-template.html')
function MyController($templateCache) {
$templateCache.put('app/my-included-template.html', myIncludedTemplate)
}
to make the require statement work with webpack, you'll need am html loader configured, i have this to do it in my module rules array...
{
test: /\.html$/,
use: [
'html-loader'
],
},
this particular implementation will require you to npm install --save-dev html-loader
this will instruct webpack to inline your template to the source file, and then your controller will immediately put it into the template cache so that it can be loaded correctly without worrying about the webpack bundle structure itself as angular will check the template cache before loading remotely. This is also a generally more performant way of doing things.
you can also do something similar when defining your directive / component templates:
template: require('./my-directive-template.html'),
which yields the same benefits of webpack just inlining the template so it doesn't need to be loaded remotely.
I'm a newbie to RequireJS I have a ReactJS app with index.jsx as an entry point
// index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
export function callBackForRequirejs() {
return "testing";
}
When I load my build via RequireJS I get these callbacks
require(["/path/to/bundle"], function(callback) {
console.log(callback) // I get "callBackForRequirejs"
}, function(err){
console.log(err)
});
But when I do code splitting I'm getting undefined in the callback, for code splitting I'm using these configs
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
}
}
}
}
UPDATE:
Actually, my react app is a plugin for some external app, the external app loads my plugin via RequireJS. The code inside an external app is something like this
case 1:
require(['/pathof/my/react/plugin/bundle.js'],
function(callbackwhenpluginloads){
callbackwhenpluginloads()
})
Since the size of my bundle.js is very large so I decided to split it into two parts one which comes from node_modules and one from my code
Now the external plugin loads my react plugin something like this
case 2:
require(['/pathof/my/react/plugin/bundle.js',
'/pathof/my/react/plugin/vendor.js' ], function(callbackwhenpluginloads){
callbackwhenpluginloads() // callbackwhenpluginloads is undefined
})
I'm getting undefined callback when the external app loads my plugin in
Actually, based on RequireJS docs for starting you did the following way and it works well:
require(['/path/to/bundle.js'], function(callback) {
console.log(callback) // you get callbackForRequireJS
}, function(error) {
console.log(error)
});
And now you did a code-splitting on your project, so you should consider this the vendor.js is like a dependency to split bundle.js file. so you should follow this example to load the dependencies at the first and then run the other split code. so your code is something like below:
requirejs.config({
paths: {
reactApp: 'path/to/bundle.js'
},
deps: ['path/to/vendor.js'],
});
require(['reactApp'], function(callback) {
console.log(callback) // it should works now
}, function(error) {
console.log(error)
});
Or there is another way that I don't recommend it:
require(['path/to/vendor.js'], function() {
require(['path/to/bundle.js'], function(callback) {
console.log(callback) // it should works now
}, function(bundleError) {
console.log('bundleError', bundleError)
});
}, function(vendorError) {
console.log('vendorError', vendorError)
});
It seems, for code splitting you are using the webpack. webpack and require js don't really get along.
you should try vanilla JS instead.
<script onload="handleOnLoad()" />
Or go for a npm package.
react-load-script - npm
For simplicity, I'll be referring to my Angular 1x version (1.6) as AngularJS and Angular 2/4x (4.0) as Angular.
I've been working on migrating a large AngularJS app to Angular, using the UpgradeModule approach as documented in the official documentation.
The app is running fine but I'm now trying to run all of the existing unit tests via Karma, and after quite a bit of Googling I'm struggling to understand exactly how my Karma config needs to be set up.
Even though my app is now a hybrid of Angular and AngularJS, all of my existing modules are still written in AngularJS. **I haven't yet added any Angular modules except for the root module that bootstraps AngularJS.
My app is compiled using a combination of gulp > browserify > tsify. Here is a snippet of my build steps:
return function() {
var bundler = browserify([
'src/app.d.ts',
'src/app.ts',
'src/main.module.ajs.ts'
], {
debug: true
})
.plugin(tsify)
.transform(babelify.configure({
presets: ["es2015"]
}));
return bundler
.bundle()
.pipe(source('main.js'))
.pipe(buffer())
.pipe(sourcemaps.init({
loadMaps: true,
sourceRoot: '/src'
}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(paths.scripts.dest));
This is the main entry file to my app:
app.ts
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { UpgradeModule } from '#angular/upgrade/static';
import { AppModule } from './main.module';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.documentElement, ['main']);
});
This is the Angular module:
main.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { UpgradeModule } from '#angular/upgrade/static';
#NgModule({
imports: [
BrowserModule,
UpgradeModule
],
})
export class AppModule {
ngDoBootstrap() {}
}
This is the AngularJS module:
main.module.ajs.ts
import './authentication/authentication.module';
import { MainController } from './main.controller';
import { CONFIGURATION } from '../config';
angular
.module('main', [
'authentication',
])
.controller('MainController', MainController)
.config(applicationRouting)
.run(applicationInit)
.constant('CONFIGURATION', CONFIGURATION);
function applicationInit($rootScope, CONFIGURATION) {
$rootScope.CONFIGURATION = CONFIGURATION;
}
function applicationRouting($routeProvider, $analyticsProvider) {
$analyticsProvider.firstPageview(false);
$analyticsProvider.virtualPageviews(false);
$routeProvider
.when('/?', {
reloadOnSearch: false
})
.otherwise({
redirectTo: '/'
});
}
..and finally, my karma config file:
karma.conf.js
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['browserify', 'jasmine'],
plugins: ['karma-jasmine', 'karma-chrome-launcher', 'karma-coverage', 'karma-ng-html2js-preprocessor', 'karma-browserify'],
files: [
'node_modules/jquery/dist/jquery.js',
'node_modules/angular/angular.js',
'node_modules/angular-route/angular-route.min.js',
'node_modules/angular-mocks/angular-mocks.js',
'node_modules/lodash/lodash.min.js',
'node_modules/angular-messages/angular-messages.min.js',
'node_modules/angular-sanitize/angular-sanitize.min.js',
'node_modules/vis/dist/vis.min.js',
'node_modules/moment/min/moment.min.js',
'node_modules/pikaday/pikaday.js',
'node_modules/filesaver.js/FileSaver.min.js',
'node_modules/angulartics/src/angulartics.js',
'node_modules/angulartics/dist/angulartics-piwik.min.js',
'node_modules/jsencrypt/bin/jsencrypt.min.js',
'node_modules/d3/d3.min.js',
'node_modules/node-uuid/uuid.js',
'node_modules/angular-vs-repeat/src/angular-vs-repeat.js',
'src/**/*.module.js',
'src/**/!(*.spec).js',
'src/**/*.spec.js',
'src/**/*.tpl.html'
],
browserify: {
debug: true,
transform: [
['babelify', {
presets: ['es2015']
}]
]
},
preprocessors: {
'src/app.d.ts': ['browserify'],
'src/app.ts': ['browserify'],
'src/main.module.ajs.ts': ['browserify'],
'src/**/!(*.spec).js': ['browserify'],
'src/**/*.tpl.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
stripPrefix: 'src/',
moduleName: 'dir-templates'
},
reporters: ['dots'],
colors: true,
port: 9018,
runnerPort: 9101,
autoWatch: true,
browsers: [
'Chrome'
],
captureTimeout: 5000,
logLevel: 'DEBUG'
});
};
As you can see in the config file, I include all of my app's third party libraries. Before switching to the hybrid app, this set up worked fine, but I assume that now my app is essentially 'wrapped' with the new Angular framework, I'm gonna need to do some configuration changes.
I'm just not entirely clear what needs to happen. When I try to run my tests with this set up, I get the following error:
Error: [$injector:modulerr] Failed to instantiate module routing due to:
Error: [$injector:modulerr] Failed to instantiate module authentication due to:
Error: [$injector:modulerr] Failed to instantiate module utils due to:
Error: [$injector:modulerr] Failed to instantiate module timeline due to:
Error: [$injector:modulerr] Failed to instantiate module events due to:
Error: [$injector:modulerr] Failed to instantiate module rest due to:
Error: [$injector:modulerr] Failed to instantiate module main due to:
Error: [$injector:nomod] Module 'main' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.6.1/$injector/nomod?p0=main
at node_modules/angular/angular.js:68:12
at node_modules/angular/angular.js:2183:17
at ensure (node_modules/angular/angular.js:2107:38)
at module (node_modules/angular/angular.js:2181:14)
at node_modules/angular/angular.js:4736:22
at forEach (node_modules/angular/angular.js:357:20)
at loadModules (node_modules/angular/angular.js:4720:5)
at node_modules/angular/angular.js:4737:40
at forEach (node_modules/angular/angular.js:357:20)
at loadModules (node_modules/angular/angular.js:4720:5)
So it's clearly not able to find the 'main' AngularJS module in order to run the tests.
Any help will be greatly appreciated! Let me know if you need more information.
Well this is a really old question and I don't know if it's still relevant but here it is:
There is a golden method of UpgradeAdapter called registerForNg1Tests() that you should try out. Here is a complete guide.
I'm trying to write a simple Angular 2 application which consumes a CommonJS Node module (Node Yelp). Angular 2 by default uses SystemJS which has the ability to load different module formats.
I have tried several different SystemJS configurations and import statements, but all of them seem to end with
SyntaxError: Unexpected token <(…)
Currently, my SystemJS configuration looks like
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
},
map: {
yelp: 'node_modules/yelp'
}
});
System.import('app/main')
.then(null, console.error.bind(console));
and my simple AppComponent.ts
import {Component} from 'angular2/core';
import Yelp from 'yelp';
#Component({
selector: 'app',
templateUrl: '/app/app.component.html'
})
export class AppComponent {
constructor(yelp: Yelp) {
console.log(yelp);
}
}
I'm still trying to wrap my head around the whole module system, so I'm not exactly sure what to change here. Any results online seem to be out dated, or not direclty related to loading CommonJS node modules with SystemJS.
I think that you could try something like that:
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
},
yeld: {
main: index.js
}
},
map: {
yelp: 'node_modules/yelp'
}
});
and
import * as Yelp from 'yelp';
The solution, as I expected, turned out to be an easy one.
Don't try roll your own System.config when using NPM packages in Angular 2
Instead, use jspm to install packages. By doing so, all of the System.config will be taken care of by jspm. In this particular case, it was as easy as
jspm install npm:yelp
Then just adding
import Yelp from 'npm:yelp#1.0.1';
to the top of my AppComponent.ts file