We've got a rather large project written in angularjs and are moving gradually to angular 4. The plan is to first rewrite everything to typescript + angularjs components. We've set up an empty angularjs+webpack+typescript project and are converting legacy angularjs modules to typescript. This works fine, but because of the size of the project we would like to add the 'old' angularjs modules for now and execute those scripts so we have a full working project.
I haven't found a way to make this work. So basically we've got (I've omitted some details for brevity):
app.module.ts:
import * as angular from 'angular';
import { moduleName as module1 } from './app/converted.module1';
import { moduleName as module1 } from './app/converted.module2';
export const moduleName =
angular.module('application', [
module1,
module2,
'legacy_module_3',
'legacy_module_4'
]).name;
So module1 and module2 are already converted typescript modules. Module 3 and module 4 not. We don't want to convert those yet but do want to reference them. Lets say those modules reside in '/frontend/module3.js' and '/frontend/module4.js', how would I make this work (executed js code) with webpack?
Consider just biting the bullet and doing minimal conversion on everything in one go.
I just went through a similar exercise converting an existing angularjs project to use webpack. The conversion needed for each module is small enough that I just converted all of the modules. So where we had:
angular.module('somemodule').controller(function(){ ... })
I changed those to:
export default function SomeController() { ... }
and the module declaration files all now look like:
import SomeController from './some.controller'
export default angular.module('SomeModule', [])
.controller(SomeController)
.name;
Then the top level:
import SomeModule from './some/module'
angular.module('app', [ SomeModule ]);
It took a little while, but as the changes are largely mechanical I was able to just work systematically through the entire application. Some sub-folders were just using the 'app' module name, so I added a 'module.js' file in each folder with an appropriate module name, but otherwise there weren't any real changes to be made.
I also had to change all of the template urls into imports and I imported the '.scss' file into the top level of the app (though that wasn't really required).
Next step will be to convert controllers and directives to components, but that should be pretty straightforward now.
You've got to export each one of your modules and then import them in your app module. Notice the following example:
//..import your other ts modules
import module3 from './frontend/module3.js' //This have to be relative path
import module4 from './frontend/module4.js'
export const moduleName =
angular.module('application', [
module1,
module2,
module3.name ,
module4.name
]).name;
Also notice that your old js modules should export a module:
e.g. filters module.
import angular from 'angular';
import myNiceFilter from './myNiceFilter.filter';
var filters = angular.module('filters',[]);
filters.filter('myNiceFilter', myNiceFilter);
export default filters;
Related
I have convert AngularJS application to es6 using webpack and import/export syntax.
Everything works perfect except this keyword.
Since webpack wrap all my code during compilation into iife function (modules), the keyword this gets undefined in functions like:
.controller( …, function() {
...
this.myFunc = function() {
someFunction().then(function(data) {
this.someVar = data;
// this === window
});
});
});
In normal angular application without bundling this gets window Object.
I do not want to make a big changes except working with webpack (I have a lot of code places that have that). Is there any way to keep this to point window object in webpack?
Webpack does force code to use "strict mode". The problem comes from the use of ES6 import statements.
From the Docs:
The static import statement is used to import bindings which are exported by another module. Imported modules are in strict mode whether you declare them as such or not.
For more information, see
MDN JavaScript Reference - import statement
Now I'm moving to a hybrid angular/angularjs project. But I stuck with import styles problem.
For example, my simple angularJs component:
import template from './simple.html';
import controller from './simple.controller.js';
import './simple.less'; // <-- Look at
export const SimpleComponent = {
template,
controller
};
I expect that styles will be extracted and included in the project.
Before I switched to the angular-CLI all magic works because of 'MiniCssExtractPlugin'.
If I create angular components:
#Component({
selector: 'app-simple',
templateUrl: './simple.html'
styleUrls: ['./simple.less']
})
All styles add correct. The same, if I it with angular.json ->
(path) projects.projectName.architect.build.options.styles
"styles": [ "src/assets/styles/index.less" ]
Now I suggest 2 ways to solve the problem (first doesn't work, second will be in a pinch):
1) Add "extractCss":true rule in angular.json -> projects.projectName.architect.serve.options. But it doesn't work.
I create issue on github about "extractCss" option.
But maybe I don't understand what exactly "extractCss" option means, and delegate 'MiniCssExtractPlugin' plugin functionality to it?
2) Create 'app.less' in 'src/app' folder and add all component styles to it. After that include it to 'angular.json' -> "styles": ["src/app/app.less"]. But it takes a lot of overhead because we have a lot of components =)
Thank you for attention =)
I'm in the process of migrating to webpack using typescript and I have some script dynamically generated into my index.html like so
<script>(function(modules) { code inside ... })</script>
How would I import code (pretty straight compiled typescript to javasript code) from this script into my main.ts file (the entry point)? For example
import whateverFunction from 'index.html'
Of course that doesn't work but I would love to see the right way to implement it. Thanks in advance.
If you defined a variable on index.html and you want to use it in typescript you need to do this:
declare var prod: boolean;
declare var version: string;
export class whateverName{
}
you should use the same name that used in index.html file.
I'm using gulp to combine my scripts in order to load only one file in HTML (make it faster).
Here's a sample code, name of libraries don't matter much, you'll get the idea :
// gulpfile.js
mix.scripts([
'vendor/jquery-2.1.1.min.js',
'vendor/angular.js',
'vendor/slideout.min.js',
'vendor/dirPaginate.js',
'vendor/cookie.js'
], 'public/js/libs.js');
And then I do this :
// app.js
let app = angular.module('app', ['angular-slideout', 'cookie', 'dir-paginate'], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
});
export default app;
I only use one file to load every NG library in my project, and then I import this app in my controllers. Now this is only an example, but I already have conflicts depending on the order of mixing these scripts in.
Any advice on processing this ? I already had to ditch some libs I wanted to use because they were conflicting with others. Going on this way, this looks like a dead end.
I understand that requirejs and browserify can load my files dependent on its current context, and that it is amazing. I would really prefer to use the #section sections syntax that the razor engine uses. Was just wondering if there is a way to implement this into a typescript / angularjs application.
for example
index.html
#renderSection scripts;
// which could turn into something like
<script data-render="scripts"></scripts>
// the app.run() could declare all the scripts that will be needed on every
// page view
view.html
<script ng-section-repeat="injected in injection"></script>
// the ng-section-repeat is basically taking all the items in the
// typescript constructor and then finding out which ones are needed for
// that view.
I like the idea injecting application file dependencies in the view , without a configuration file and all the added extras that comes with the loaders.
I just want to easily define what files are needed in the actual view and get them loaded, with angular's dependency injection handling the dependency itself.
If you are handling all your dependencies with $inject then , as far as i can tell, dependency is technically already setup in the controllers, all one would need, is to load this as it is called. Which could even eliminate the need for the #section scripts completely
Update:
What i have done to sort of replicate the module loaders is to just use gulp-concat and define the file order in my gulp.config.js and then pass it to the gulp-src before running $.concat .this allows me to have the files in the gulp steam , in dependent order . They are however loaded on the first load. With gulp-uglify the files are tiny ( its now at 566Kb with 16 external libraries loading in 69ms . To put that into perspective it takes 209ms to load one google font ).
I dont know maybe i am not understanding browserify correctly but i honestly struggle to see the need for it, its seems extremely convoluted for something so simple
It is possible using external modules and an injector to do what you asked for:
I just want to easily define what files are needed in the actual view
import {UserFactory} from 'models/userFactory';
import {UserValidator} from 'models/userValidator';
import {Inject} from 'angular2/di';
and get them loaded, with angular's dependency injection handling the dependency itself.
Note: My example uses angular 2.x because I less familiar with angular 1.x and I'm sure you can do something really similar...
class SomeComponent {
userName: string;
userRating: number;
rating: number;
constructor(
#Inject(UserFactory) UserFactory
#Inject(UserValidator) UserValidator
)
{
this.UserFactory = UserFactory;
this.UserValidator = UserValidator;
}
}
Then you can use Browserify to create a bundle.js file that can be executed in a web browser.