Is it worth to migrate from Angular 2 to Angular 4? - migration

Hello SO community and Angularians!
So, I am midway developing a huge platform in Angular 2. And I realized that many external libraries and dependencies for Angular 2 are migrating to the new Angular 4. Giving me many errors, obviously.
I could fork these libraries and use the forked versions and subscribe to main library development or, I could just upgrade to Angular 4 my project.
Questions to be answered in order to determinate if it's worth for me to migrate:
Compatibility with Angular 2.4
I have found some adaptations to ensure compatibility with legacy, like this: https://github.com/angular/angular/commit/e99d721
Changes app wide
Do I have to go through my whole app and start fixing things?
I mean, are main functionalities reworked in such way that I will have to review many of them?
Or, are there many build/core incompatibilities that will keep me days occupied fixing compile errors/warnings instead of developing?
I am not asking for someone to do the research for me, I am asking people that maybe already went through this process or simply know well both versions in order to give me some experience tips, clarifications, etc.
At the moment, I am doing my research here:
https://github.com/angular/angular/blob/master/CHANGELOG.md
http://angularjs.blogspot.it/2017/03/angular-400-now-available.html
https://learninglaravel.net/angular-4-new-features-and-improvements
UPDATE
I just migrated to Angular 4. The link that #PierreDuc put in his answer is a very nice tool to have a decent guideline in the migration process.
I would recommend:
Read new features and update yourself with Angular 4. This was specially useful: https://angularjs.blogspot.it/2017/03/angular-400-now-available.html
Follow Angular's guideline and modify your project: https://angular-update-guide.firebaseapp.com/
I would also recommend to commit your current project, create a new branch in your dev repository and proceed with migration in that branch.
An issue that I encountered:
Input, Output and ContentChild will be imported from a wrong path.
My case:
import { Component, OnInit, OnDestro } from '#angular/core';
import { Input, ContentChild } from "#angular/core/src/metadata/directives";
Solution:
import { Component, OnInit, OnDestroy, Input, ContentChild } from '#angular/core';

If you check the changelog there are a couple things you need to keep in mind:
Before updating
Ensure you don't use extends OnInit, or use extends with any lifecycle event. Instead use implements <lifecycle event>.
Stop using DefaultIterableDiffer, KeyValueDiffers#factories, or IterableDiffers#factories
Stop using deep imports, these symbols are now marked with ɵ and are
not part of our public API.
Stop using Renderer.invokeElementMethod as this method has been
removed. There is not currently a replacement.
During the update
Update all of your dependencies to version 4 and the latest typescript.
If you are using Linux/Mac, you can use: npm install
#angular/{animations,common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router}#4.0.0
typescript#latest --save
If you use animations in your application, you should import
BrowserAnimationsModule from #angular/platform-browser/animations in
your App NgModule.
Replace RootRenderer with RendererFactory2.
Replace Renderer with Renderer2.
After the update
Rename your template tags to ng-template.
Replace OpaqueTokens with InjectionTokens.
If you call DifferFactory.create(...) remove the ChangeDetectorRef
argument.
Replace ngOutletContext with ngTemplateOutletContext.
Replace CollectionChangeRecord with IterableChangeRecord
source

Angular team has announced , let's not call angular 2 or angular 4 let's call it Angular and there will be major update for every 6 months.I have faced the issue in angular v4.0.0 so change the configuration in webpack
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)#angular/,
helpers.root('./src'), // location of your src
{} // a map of your routes
),
And install #angular/animations package and import in app.module.ts file
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
#NgModule({
imports: [
BrowserAnimationsModule
]
})
I will prefer to update to latest version of angular. Angular V4.0.0 has reduced the packages weight and they have increased the performance.

Related

Bundling a plugin with Rollup but having duplicate Vue.js package imported in the client app's bundle (Nuxt)

Dear Stack Overflow / Vue.js / Rollup community
This could be a noob question for the master plugin developers working with Vue and Rollup. I will write the question very explicitly hoping that it could help other noobs like me in the future.
I have simple plugin that helps with form validation. One of the components in this plugin imports Vue in order to programatically create a component and append to DOM on mount like below:
import Vue from 'vue'
import Notification from './Notification.vue' /* a very simple Vue component */
...
mounted() {
const NotificationClass = Vue.extend(Notification)
const notificationInstance = new NotificationClass({ propsData: { name: 'ABC' } })
notificationInstance.$mount('#something')
}
This works as expected, and this plugin is bundled using Rollup with a config like this:
import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import { terser } from 'rollup-plugin-terser'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
input: 'src/index.js',
output: {
name: 'forms',
globals: {
vue: 'Vue'
}
},
plugins: [
vue(),
babel(),
resolve(),
commonjs(),
terser()
],
external: ['vue']
}
As you can see, Vue.js is getting externalised in this bundle. The aim (and the assumption) is that the client app that imports this plugin will be running on Vue, therefore there's no need to bundle it here (assumption).
The very simple src/index.js that the bundler uses is below:
import Form from './Form.vue'
export default {
install(Vue, _) {
Vue.component('bs-form', Form)
}
}
Rollup creates 2 files (one esm and one umd) and references them in in the plugins package.json file like below:
"name": "bs-forms",
"main": "./dist/umd.js",
"module": "./dist/esm.js",
"files": [
"dist/*"
],
"scripts": {
"build": "npm run build:umd & npm run build:es",
"build:es": "rollup --config rollup.config.js --format es --file dist/esm.js",
"build:umd": "rollup --config rollup.config.js --format umd --file dist/umd.js"
}
Everything works as expected up to this point and the bundles are generated nicely.
The client app (Nuxt SSR) imports this plugin (using npm-link since it's in development) with a very simple import in a plugin file:
/* main.js*/
import Vue from 'vue'
import bsForms from 'bs-forms'
Vue.use(bsForms)
This plugin file (main.js) is added to nuxt.config.js as a plugin:
// Nuxt Plugins
...
plugins: [{src: '~/plugins/main'}]
...
Everything still works as expected but here comes the problem:
Since the clients is a Nuxt app, the Vue is imported by default of course but the externalised Vue module (by the forms plugin) is also imported in the client. Therefore there is a duplication of this package in the client bundle.
I guess the client app can configure its webpack config in order to remove this duplicated module. Perhaps by using something like a Dedupe plugin or something? Can someone suggests how to best handle situation like these?
But what I really want to learn, is the best practice of bundling the plugin at the first place, so that the client doesn't have to change anything in its config and simply imports this plugin and move on.
I know that importing the Vue.js in the plugin may not be a great thing to do at the first place. But there could be other reasons for an import like this as well, for example imagine that the plugin could be written in Typescript and Vue.js / Typescript is written by using Vue.extend statements (see below) which also imports Vue (in order to enable type interface):
import Vue from 'vue'
const Component = Vue.extend({
// type inference enabled
})
So here's the long question. Please masters of Rollup, help me and the community out by suggesting best practice approaches (or your approaches) to handle situations like these.
Thank you!!!!
I had the same problem and I found this answer of #vatson very helpful
Your problem is the combination of "npm link", the nature of nodejs module loading and the vue intolerance to multiple instances from different places.
Short introduction how import in nodejs works. If your script has some kind of library import, then nodejs initially looks in the local node_modules folder, if local node_modules doesn't contain required dependency then nodejs goes to the folder above to find node_modules and your imported dependency there.
You do not need to publish your package on NPM. It is enough if you generate your package locally using npm pack and then install it in your other project npm install /absolute_path_to_your_local_package/your_package_name.tgz. If you update something in your package, you can reinstall it in your other project and everything should work.
Here is the source about the difference between npm pack and npm link https://stackoverflow.com/a/50689049/6072503.
I have sorted this problem with an interesting caveat:
The duplicate Vue package doesn't get imported when the plugin is used via an NPM package (installed by npm install -save <plugin-name> )
However, during development, if you use the package vie npm link (like npm link <plugin-name>) then Vue gets imported twice, like shown in that image in the original question.
People who encounter similar problems in the future, please try to publish and import your package and see if it makes any difference.
Thank you!

React native Fabric autolink error with react 60.0 and above

I have upgraded to my app to react-native 60.4 which support Autolinking all packages so that you dont have to manually go about setting things up and thus lowers the chances of error.
The problem is most of the packages have still not gotten compatible with this process and henceforth the app completely breaks.
my error is with https://github.com/corymsmith/react-native-fabric
referring to an issue on the repo for the same -> https://github.com/corymsmith/react-native-fabric/issues/225, which still remains unanswered.
I started giving it a try by forking the repo and understanding the auto link process given by react native.
In the package.json of the node_module package i replaced
"rnpm": {
"android": {
"packageInstance": "new FabricPackage()"
}
},
with file in the package root react-native.config.js
module.exports = {
dependencies: {
'react-native-fabric': {
platforms: {
android: {
"packageImportPath": "import com.smixx.fabric.FabricPackage;",
"packageInstance": "new FabricPackage()"
}
}
}
}
};
I also updated the build gradle to 3.4.1 from 3.1.0
My react native app is able to now find the package.
But when i call the package in my react component i get NoClassDefFoundError, which means that class is not found.
Anybody else gave this a try and have a solution please let me know.
Try to unlink with react-native unlink and then re run your code again.
Putting it here from the above comment to make it more clear:
Ok i got this to work by changing the forked repo -> (adding a react-native.config.js in the root of the package with with auto discovery and link configurations), but i think the only scalable solution i see right now is to degrade to RN ^59.0 as not a lot of packages have auto link config changes. So will wait for RN 60.4 to mature and then upgrade to it in about a month. In addition to this fabric is currently migrating to firebase and plans to complete by year end. This mean that anyways the sdk integration is going to be obsolete and hence this package too.
Also this issue is majorly related to react-native-fabric and not RN itself.

webpack-resolve-alias to resolve dependecy's sub-dependency

I'm sort of stuck with one problem and googling it for about three hours brought me nowhere.
Here's the problem. I'm trying to develop my own custom PDF viewer based on PDF.JS lib. Officially it is distributed on npm as pdfjs-dist package. However I need to extend a few classes that are not accessible in pdfjs-dist. So I npm install'ed or yarn add'ed the original repo https://github.com/mozilla/pdf.js.git. This way I have access to classes I need. Inside pdf.js there are core lib that is stored in pdf.js/src/ and a pdf-viewer app that is stored in pdf.js/web/.
Inside that pdf.js/web/ app core lib (pdf.js) is referenced via pdfjs-lib alias that is resolved to pdf.js/src/ during pdf.js inner build process by gulp.
For example pdf.js/web/base_viewer.js:
import { AnnotationLayerBuilder } from './annotation_layer_builder';
import { createPromiseCapability } from 'pdfjs-lib';
import { PDFPageView } from './pdf_page_view';
So now I'm trying to import that pdf.js/web/base_viewer.js in my app that is using latest Webpack 4 (I guess), and this pdfjs-lib sub-dependency is not resolved.
I've tried webpack's resolve-alias mechanism (https://webpack.js.org/configuration/resolve/):
resolve: {
alias: {
'pdfjs-lib': path.resolve(__dirname, './node_modules/pdf.js/src/')
},
}
...but looks like it resolves dependencies only of my own App, but not sub-dependencies of my dependency.
Just in case I'm building Vue 3.0 app using vue-cli and access webpack config this way: https://cli.vuejs.org/guide/webpack.html, but don't think it matters.
Any help from Webpack gurus here?
Thanks.

Unit test case is failing in my React app because of some issue in fabric

I am new to react and also wanted to use office react ui for one of our requirement i followed the git hub and able to use office ui react components in my components but while running my first test case for App.js it is giving me below error.
E:\net_react\my-new-app\ClientApp\node_modules\office-ui-fabric-react\lib\Fabric.js:1
({"Object.":function(module,exports,require,__dirname,__filename,global,jest){export * from './components/Fabric/index';
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/ScriptTransformer.js:289:17)
at Object. (src/components/Login.js:13:592)
at Object. (src/components/Home.js:2:14)
And i have an import statement in my Login.js
import { Fabric } from '../../node_modules/office-ui-fabric-react/lib/Fabric';
The error is because your test harness does not support ES 6 modules (which is what is in lib in Fabric 6).
Try importing instead from office-ui-fabric-react/lib-commonjs/Fabric or office-ui-fabric-react (which has bundle size implications unless you're able to utilize Tree Shaking) or modify your test harness's module map to redirect lib/ imports into lib-commonjs.
Update
To elaborate on the answer above, the Fabric release notes has guidance for Jest configuration:
moduleNameMapper: {
"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1"
}

After bundling my aurelia app I get a: No PLATFORM.Loader error

After bundling a simple aurelia application with jspm bundle-sfx I get the following error:
No PLATFORM.Loader is defined and there is neither a System API (ES6) or a Require API (AMD) globally available to load your app.
An example application: https://github.com/Baudin999/jspm-bundling-test
You can use: npm run setup:dev in a non windows env to switch back to the dev settings (which is just a comment/uncomment in the ./src/client/index.html) and you can use npm run setup:prod to switch back to the production environment, bundling will automatically be triggered. all other scripts can be found in the package.json.
I can't link to other questions because I haven't found any questions which relate to this problem. I "think" (which means absolutely nothing) that this might be related to the fact that aurelia needs a full loader even when bundling with bundle-sfx but I haven't found any ways to solve the error.
EDIT (25/01/2017 17:16): I've found out that the error is because I import the aurelia-bootstrapper.
As soon as I add: import * as bootstrapper from 'aurelia-bootstrapper'; I get the error
Please add the code how do you bootstrap your aurelia app.
There is nothing actually to import from bootstrapper apart from bootstrap function.
Which you would use in case of custom manual bootstrapping.
like in
import { bootstrap } from 'aurelia-bootstrapper'
const configure: (au: Aurelia) => {} = async function (au: Aurelia) {
au.use
.standardConfiguration();
await au.start()
au.setRoot() // or au.enchance()
})
bootstrap(configure)
in a happy path scenario with jspm - you System.import('aurelia-bootstrapper')
and it takes over finding the root node of your app and the script to configure Aurelia (main by default)
Have a look at Bootstrapping Aurelia in the docs
Oh.. and bundle-sfx is not supported there are other means to bundle aurelia apps using jspm