colinskow / angular-electron-dream-starter

:tada: An Angular Electron Starter kit featuring Webpack, Angular 4 (Router, Http, Forms, Services, ngrx, Tests, E2E, Coverage), Karma, Spectron, Jasmine, Istanbul, and TypeScript
MIT License
162 stars 54 forks source link

Adding a 3rd party library such as PrimeNG #2

Closed greg9504 closed 7 years ago

greg9504 commented 7 years ago

Hello,

I'm having a hard time adding any 3rd party modules. I've tried PrimeNG and ag-grid, with little success. I have been successful at adding a 3rd party module to the base repository ( AngularClass/angular2-webpack-starter). I then try to replicate what I did with an instance of this repository and I end up with odd errors on load:

Error: Unexpected value 'AccordionModule' imported by the module 'AppModule'. Please add a @NgModule annotation. at syntaxError (file:///D:/devtools/js/tutorials/angular-electron-dream-starter/dist/vendor.dll.js:16427:34) [] at file:///D:/devtools/js/tutorials/angular-electron-dream-starter/dist/vendor.dll.js:29321:44 [] at Array.forEach (native) [] at CompileMetadataResolver.vendor_lib.136.CompileMetadataResolver.getNgModuleMetadata (file:///D:/devtools/js/tutorials/angular-electron-dream-starter/dist/vendor.dll.js:29304:49) [] at JitCompiler.vendor_lib.136.JitCompiler._loadModules (file:///D:/devtools/js/tutorials/angular-electron-dream-starter/dist/vendor.dll.js:40485:64) []

I've found this on the web https://github.com/angular/angular/issues/15763 but not sure how that relates to this project.

First this is what I did to get PrimeNG to work with a fresh clone of AngularClass/angular2-webpack-starter:

open /src/app/app.module.ts add line 2 import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; add line 32 import { AccordionModule } from 'primeng/components/accordion/accordion'; add BrowserAnimationsModule and AccordionModule (this is from primeng) to imports (line ~61):

imports: [ // import Angular's modules
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    HttpModule,
    AccordionModule,
    RouterModule.forRoot(ROUTES, { useHash: true, preloadingStrategy: PreloadAllModules })
  ],

in /src/app/home/home.component.ts line 3 add

<p-accordion>
        <p-accordionTab header="Godfather I" [selected]="true">
            The story begins as Don Vito Corleone, the head of a New York Mafia family, overseeshis daughter's wedding. His beloved son ichael has just come home from the war, but does not intend to become part of his father's business. T hrough Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family, kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
        </p-accordionTab>
        <p-accordionTab header="Godfather II">
            Francis Ford Coppola's legendary continuation and sequel to his landmark 1972 film, The_Godfather parallels the young Vito Corleone's rise with his son Michael's spiritual fall, deepening The_Godfather's depiction of the dark side of the American dream. In the early 1900s, the child Vito flees his Sicilian village for America after the local Mafia kills his family. Vito struggles to make a living, legally or illegally, for his wife and growing brood in Little Italy, killing the local Black Hand Fanucci after he demands his customary cut of the tyro's business. With Fanucci gone, Vito's communal stature grows.
        </p-accordionTab>
        <p-accordionTab header="Godfather III">
            After a break of more than  15 years, director Francis Ford Coppola and writer Mario Puzo returned to the well for this third and final story of the fictional Corleone crime family. Two decades have passed, and crime kingpin Michael Corleone, now divorced from his wife Kay has nearly succeeded in keeping his promise that his family would one day be completely legitimate.
        </p-accordionTab>
    </p-accordion>
<p-accordion>
        <p-accordionTab header="Godfather I" [selected]="true">
            The story begins as Don Vito Corleone, the head of a New York Mafia family, overseeshis daughter's wedding. His beloved son ichael has just come home from the war, but does not intend to become part of his father's business. T hrough Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family, kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.
        </p-accordionTab>
        <p-accordionTab header="Godfather II">
            Francis Ford Coppola's legendary continuation and sequel to his landmark 1972 film, The_Godfather parallels the young Vito Corleone's rise with his son Michael's spiritual fall, deepening The_Godfather's depiction of the dark side of the American dream. In the early 1900s, the child Vito flees his Sicilian village for America after the local Mafia kills his family. Vito struggles to make a living, legally or illegally, for his wife and growing brood in Little Italy, killing the local Black Hand Fanucci after he demands his customary cut of the tyro's business. With Fanucci gone, Vito's communal stature grows.
        </p-accordionTab>
        <p-accordionTab header="Godfather III">
            After a break of more than  15 years, director Francis Ford Coppola and writer Mario Puzo returned to the well for this third and final story of the fictional Corleone crime family. Two decades have passed, and crime kingpin Michael Corleone, now divorced from his wife Kay has nearly succeeded in keeping his promise that his family would one day be completely legitimate.
        </p-accordionTab>
    </p-accordion>

go back to command line and do: npm start you should see: image

Everything works.

I repeat the above steps but instead clone this repository. I run into two problems:

Any hints on what steps I should follow when adding a module like PrimeNG to this?

Things I've tried:

Thanks Greg.

colinskow commented 7 years ago

I don't believe I've changed anything from AngularClass/angular2-webpack-starter that would impact this behavior. From the error message it looks like it is a Webpack DLL issue. A couple things to check:

1) Test if it works in a production build 2) Try adding NGPrime to the list of vendor DLLs here: https://github.com/colinskow/angular-electron-dream-starter/blob/master/config/webpack.dev.js#L160

I've been working on the Electron port and haven't yet had a chance to customize it much to work out the issues. So I apologize I can't help you much at this point.

colinskow commented 7 years ago

Import your stylesheets here instead of in /config/head-config.common.js.

greg9504 commented 7 years ago

Hello,

Thanks for the reply, it has me on the right track. I had previously tried adding Primeng to the vendor dlls, I tried adding both as: 'primeng', and

{
     //see https://github.com/shlomiassaf/webpack-dll-bundles-plugin/issues/16
      name: 'primeng',
      path: 'primeng/primeng'
},

neither worked, or generated any errors (perhaps that's meaningful).

Before trying the production builds I commented it out of the vendor dll settings in webpack.dev.js.

Then I did:

Then ran it, still same problem.

Then I tried:

and it runs!

I haven't got the styles sorted out yet but that shouldn't be a problem.

So the question is what is different between these builds ? I'll try to figure it out but if you have any ideas where to look that would be great.

Thanks for your help.

colinskow commented 7 years ago

To get PrimeNG working with Angular 4, you need to specify version 4.0.0-rc.4. The latest stable release (installed by default with npm install) will only work with Angular 2.

https://www.primefaces.org/primeng-2-0-4-released/

It is likely that you were using the Angular 2 version of angular2-webpack-starter, and the Angular 4 version of my repo... which would explain the different behavior.

greg9504 commented 7 years ago

Hello Colin, No I was using the correct version of Primeng and Angular. In BOTH cases it was: Primeng 4.0.0-rc.3 and rc.4 (tried both) and Angular 4 (4.0.2 and 4.0.3)

FWIW doing npm install --save primeng installs the latest 4.0 release not 2.0.x, here I did npm init then install,:

Directory of D:\devtools\js\tutorials\testprimeng

4/28/2017 09:12 AM

. 4/28/2017 09:12 AM .. 4/28/2017 09:12 AM 207 package.json 1 File(s) 207 bytes 2 Dir(s) 458,858,405,888 bytes free

:\devtools\js\tutorials\testprimeng>npm install --save primeng estprimeng@1.0.0 D:\devtools\js\tutorials\testprimeng -- primeng@4.0.0-rc.5 <--- installs 4.0.0.x

This is one of the first things I verified. This is a section of package.json that I used when testing latest of your repo:

"dependencies": {
    "electron-devtools-installer": "^2.2.0",
    "font-awesome": "^4.7.0",
    "primeng": "^4.0.0-rc.4",
    "rxjs": "~5.3.0"
  },
  "devDependencies": {
    "@angular/animations": "~4.0.3",
    "@angular/common": "~4.0.3",
    "@angular/compiler": "~4.0.3",
    "@angular/compiler-cli": "~4.0.3",
    "@angular/core": "~4.0.3",
    "@angular/forms": "~4.0.3",
    "@angular/http": "~4.0.3",
    "@angular/platform-browser": "~4.0.3",
    "@angular/platform-browser-dynamic": "~4.0.3",
    "@angular/platform-server": "~4.0.3",
    "@angular/router": "~4.0.3",
    "@angularclass/conventions-loader": "^1.0.13",
    "@angularclass/hmr": "~1.2.2",
    "@angularclass/hmr-loader": "~3.0.2"
    ...

Note I had updated your angular from 4.0.2 to 4.0.3 to match what was in the angular2-webpack-starter project to see if that made a difference (it didn't).

Here is the package.json for angular2-webpack-starter

"dependencies": {
    "@angular/animations": "~4.0.3",
    "@angular/common": "~4.0.3",
    "@angular/compiler": "~4.0.3",
    "@angular/core": "~4.0.3",
    "@angular/forms": "~4.0.3",
    "@angular/http": "~4.0.3",
    "@angular/platform-browser": "~4.0.3",
    "@angular/platform-browser-dynamic": "~4.0.3",
    "@angular/platform-server": "~4.0.3",
    "@angular/router": "~4.0.3",
    "@angularclass/conventions-loader": "^1.0.13",
    "@angularclass/hmr": "~1.2.2",
    "@angularclass/hmr-loader": "~3.0.2",
    "core-js": "^2.4.1",
    "font-awesome": "^4.7.0",
    "http-server": "^0.9.0",
    "ie-shim": "^0.1.0",
    "jasmine-core": "^2.5.2",
    "primeng": "^4.0.0-rc.4",
    "reflect-metadata": "^0.1.10",
    "rxjs": "5.0.2",
    "zone.js": "~0.8.5"
  },
  "devDependencies": {
    "@angular/compiler-cli": "~4.0.3",
    "@types/hammerjs": "^2.0.34",
    "@types/jasmine": "2.5.45",
    "@types/node": "^7.0.13",
    "@types/source-map": "^0.5.0",
    "@types/uglify-js": "^2.6.28",
    "@types/webpack": "^2.2.15",
    ...

For your repo the only build that I have working is the: npm run build:aot When I run the resulting electron it executes normally, for any other build I get the:

Unexpected value 'AccordionModule' imported by the module 'AppModule'. Please add a @NgModule annotation.

exception. I've been looking over the webpack files to figure out why but haven't yet.

greg9504 commented 7 years ago

OK I finally figured out what the problem was. The webpack.common.js file for your repository contains: ~ line 213

    /*
     * Exclude package.json dependencies from the bundle
     *
     * See: https://webpack.js.org/configuration/externals/
     */
    externals: [dependencyExternals()]

The above code is not in the webpack.common.js from AngularClass/angular2-webpack-starter.

In an AOT build I'm guessing the dependencies are pre-compiled into the bundle, and that's why it works and primeng was loaded. From the docs I'm trying to reconcile what this means:

Each package listed in package.json under dependencies will automatically be packaged with your app and rebuilt for Electron if it contains native bindings.

Given that the above webpack dependencyExternals seems to contradict this. When I commented out the externals: [dependencyExternals()] the primeng components were loaded OK. However I have a dependency on better-sqlite3 (a module with native bindings), which if I leave externals: [dependencyExternals()] commented out no longer works (get errors from binding.js). So I've white listed primeng like:

    /*
     * Exclude package.json dependencies from the bundle
     *
     * See: https://webpack.js.org/configuration/externals/
     */
    externals: [dependencyExternals({
        // this will include `primeng`
        whitelist: ['primeng/primeng']
    })],

and for the .css files in src/styles/styles.scss

@import './../../node_modules/primeng/resources/themes/omega/theme.css';
@import './../../node_modules/primeng/resources/primeng.min.css';
@import './../../node_modules/font-awesome/css/font-awesome.min.css';

now npm build:dev and npm build:prod builds work.

If you have a chance and could explain why primeng needs to be white listed while a module like better-sqlite3 needs to be excluded I'd love to know.

Thanks. Greg.

colinskow commented 7 years ago

Hi Greg,

You don't need to whitelist PrimeNG. You simply need to make it a devDependency.

Every module that is listed under dependencies is packaged in the node_modules directory of the built app and is not parsed by Webpack.

See this part of the README: https://github.com/colinskow/angular-electron-dream-starter#managing-dependencies

Your dependencies are modules that are needed by the Electron runtime. DevDependencies are parsed and bundled by Webpack.

SQLite3 has native node dependencies so it won't work if bundled by Webpack. It should be included in dependencies.

Remove the whitelist and try it as a simple devDependency. It should work as expected.

greg9504 commented 7 years ago

Hello Colin,

OK tried that and it does indeed work.

I feel stupid... I read that doc over and over thinking I had things right.

With your explanation I think I understand the reasons for the separation. The confusing part for me (being new to Electron and Web dev) is that most examples for 3rd party modules recommend that they go in "dependencies". And when I read the npm install docs

"dependencies": these packages are required by your application in production "devDependencies": these packages are only needed for development and testing

Intuitively to me primeng is a dependencies package. However with your explanation I understand what you've done for Electron.

Thanks for the help. Greg.

colinskow commented 7 years ago

Yes, if you notice almost everything in my package.json is under devDependencies.

dependencies are packaged with the application runtime in production by Electron Builder. @angular and its modules are compiled and tree shaken by Webpack, so the original files don't need to be packaged with the application.

I needed a way to tell Electron what to package with the app, and dependencies vs. devDependencies seemed like the simplest distinction.