Adding Angular Material to Asp.Net Core 2 SPA

2019-04-15 23:53发布

I cant seem to get this to work. The bits and pieces I find on SO and the net are out of date and seem incomplete.

Here is my package.json:

{
  "name": "MyProj.Site",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "test": "karma start ClientApp/test/karma.conf.js"
  },
  "devDependencies": {
    "@angular/animations": "5.1.1",
    "@angular/common": "5.1.1",
    "@angular/compiler": "5.1.1",
    "@angular/compiler-cli": "5.1.1",
    "@angular/core": "5.1.1",
    "@angular/forms": "5.1.1",
    "@angular/http": "5.1.1",
    "@angular/platform-browser": "5.1.1",
    "@angular/platform-browser-dynamic": "5.1.1",
    "@angular/platform-server": "5.1.1",
    "@angular/router": "5.1.1",
    "@ngtools/webpack": "1.9.1",
    "@types/chai": "4.0.1",
    "@types/jasmine": "2.5.53",
    "@types/webpack-env": "1.13.3",
    "angular2-router-loader": "0.3.5",
    "angular2-template-loader": "0.6.2",
    "aspnet-prerendering": "^3.0.1",
    "aspnet-webpack": "^2.0.1",
    "@angular/material": "5.0.1",
    "@angular/cdk": "5.0.1",
    "awesome-typescript-loader": "3.4.1",
    "bootstrap": "4.0.0-beta.2",
    "chai": "4.0.2",
    "css": "2.2.1",
    "css-loader": "0.28.4",
    "es6-shim": "0.35.3",
    "event-source-polyfill": "0.0.9",
    "expose-loader": "0.7.3",
    "extract-text-webpack-plugin": "2.1.2",
    "file-loader": "0.11.2",
    "html-loader": "0.4.5",
    "isomorphic-fetch": "2.2.1",
    "jasmine-core": "2.6.4",
    "jquery": "3.2.1",
    "json-loader": "0.5.4",
    "karma": "1.7.0",
    "karma-chai": "0.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-jasmine": "1.1.0",
    "karma-webpack": "2.0.3",
    "preboot": "5.1.7",
    "raw-loader": "0.5.1",
    "reflect-metadata": "0.1.10",
    "rxjs": "5.4.2",
    "style-loader": "0.18.2",
    "to-string-loader": "1.1.5",
    "typescript": "2.6.1",
    "url-loader": "0.5.9",
    "webpack": "3.10.0",
    "webpack-hot-middleware": "2.21.0",
    "webpack-merge": "4.1.1",
    "zone.js": "0.8.12",
    "hammerjs": "2.0.8"
  }
}

my webpack.config.vendor.js:

const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const merge = require('webpack-merge');
const treeShakableModules = [
    '@angular/animations',
    '@angular/common',
    '@angular/compiler',
    '@angular/core',
    '@angular/forms',
    '@angular/http',
    '@angular/platform-browser',
    '@angular/platform-browser-dynamic',
    '@angular/router',
    'zone.js',
    '@angular/cdk'
];
const nonTreeShakableModules = [
    'hammerjs/hammer',
    'bootstrap',
    'bootstrap/dist/css/bootstrap.css',
    'es6-promise',
    'es6-shim',
    'event-source-polyfill',
    'jquery',
    '@angular/material/prebuilt-themes/indigo-pink.css',


];
const allModules = treeShakableModules.concat(nonTreeShakableModules);

module.exports = (env) => {
    const extractCSS = new ExtractTextPlugin('vendor.css');
    const isDevBuild = !(env && env.prod);
    const sharedConfig = {
        stats: { modules: false },
        resolve: { extensions: [ '.js' ] },
        module: {
            rules: [
                { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' }
            ]
        },
        output: {
            publicPath: 'dist/',
            filename: '[name].js',
            library: '[name]_[hash]'
        },
        plugins: [
            new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
            new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
            new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898
            new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
        ]
    };

    const clientBundleConfig = merge(sharedConfig, {
        entry: {
            // To keep development builds fast, include all vendor dependencies in the vendor bundle.
            // But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle.
            vendor: isDevBuild ? allModules : nonTreeShakableModules
        },
        output: { path: path.join(__dirname, 'wwwroot', 'dist') },
        module: {
            rules: [
                { test: /\.css(\?|$)/, use: extractCSS.extract({ use: isDevBuild ? 'css-loader' : 'css-loader?minimize' }) }
            ]
        },
        plugins: [
            extractCSS,
            new webpack.DllPlugin({
                path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
                name: '[name]_[hash]'
            })
        ].concat(isDevBuild ? [] : [
            new webpack.optimize.UglifyJsPlugin()
        ])
    });

    const serverBundleConfig = merge(sharedConfig, {
        target: 'node',
        resolve: { mainFields: ['main'] },
        entry: { vendor: allModules.concat(['aspnet-prerendering']) },
        output: {
            path: path.join(__dirname, 'ClientApp', 'dist'),
            libraryTarget: 'commonjs2',
        },
        module: {
            rules: [ { test: /\.css(\?|$)/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] } ]
        },
        plugins: [
            new webpack.DllPlugin({
                path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),
                name: '[name]_[hash]'
            })
        ]
    });

    return [clientBundleConfig, serverBundleConfig];
}

and my app.shared.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from './components/counter/counter.component';

import { MatButtonModule } from '@angular/material/button';


@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        CounterComponent,
        FetchDataComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', component: CounterComponent },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ]),
        MatButtonModule
    ]
})
export class AppModuleShared {
}

My vendor.config compiles fine. When I debug the project in VS2017, I get this error:

NodeInvocationException: Prerendering failed because of error: Error: Cannot find module "rxjs/operators/take" at webpackMissingModule (C:\Users\Mike\Source\MyProj\ClientApp\dist\main-server.js:15733:140)

Any help on where I should reference the rxjs modules would be appreciated.

2条回答
Explosion°爆炸
2楼-- · 2019-04-16 00:31

As can be seen in the package.json, @angular/material has the following dependency:

"rxjs": "^5.5.5"

You have "rxjs": "5.4.2" in your package.json, which is obviously a little behind this. I actually found a Github issue for the flex-layout angular package, which suggested uprading rxjs to 5.5 solves the same issue in that package. I just tried this with your setup and can confirm that it works using 5.5.5 as above.

EDIT: Once you've installed the updated version, you'll need to get webpack to rebuild in the correct order. You might be able to get that to happen with a solution-level rebuild of the project(s), but if not, you can run the following to force webpack to build correctly:

webpack --config webpack.config.vendor.js
webpack

You might not have webpack installed globally - if not, you can use the following (assuming Windows):

.\node_modules\.bin\webpack --config webpack.config.vendor.js
.\node_modules\.bin\webpack
查看更多
啃猪蹄的小仙女
3楼-- · 2019-04-16 00:33

Adding latest version of Angular Material in ASP.net Core 2.0 with default installed node packages is more difficult and time consuming for resolving package dependencies.

Use below version of angular material in package.json

"@angular/cdk": "^2.0.0-beta.12"

"@angular/material": "^2.0.0-beta.12"

followed by run below command to install it.

npm install --save

查看更多
登录 后发表回答