在ASP.NET MVC应用程序中集成Angular和Webpack

Leo*_*chi 9 asp.net-mvc webpack angular

我正在寻找一个可以遵循的步骤,将Angular添加到现有的MVC应用程序中,该应用程序位于我的解决方案区域.我找到了一个编写,告诉我如何使用gulp.js文件添加角度,该文件提取必要的node_modules并将我的ts文件转换为js文件.我想用webpack做同样的事情.

在此输入图像描述

目前我的package.json看起来像这样.

{
    "version": "1.0.0",
    "name": "aspnet",
    "private": true,
    "scripts": {},
    "dependencies": {
        "@angular/animations": "4.3.5",
        "@angular/common": "4.3.5",
        "@angular/compiler": "4.3.5",
        "@angular/compiler-cli": "4.3.5",
        "@angular/core": "4.3.5",
        "@angular/forms": "4.3.5",
        "@angular/http": "4.3.5",
        "@angular/platform-browser": "4.3.5",
        "@angular/platform-browser-dynamic": "4.3.5",
        "@angular/platform-server": "4.3.5",
        "@angular/router": "4.3.5",
        "@angular/upgrade": "4.3.5",
        "angular-in-memory-web-api": "0.3.2",
        "bootstrap": "3.3.7",
        "core-js": "2.5.0",
        "ie-shim": "0.1.0",
        "rxjs": "5.4.3",
        "zone.js": "0.8.16",
        "systemjs": "^0.20.18"
    },
    "devDependencies": {
        "gulp": "^3.9.1",
        "gulp-clean": "^0.3.2",
        "gulp-concat": "^2.6.1",
        "gulp-tsc": "~1.3.2",
        "gulp-typescript": "^3.2.2",
        "path": "^0.12.7",
        "typescript": "^2.4.2"
    }
}
Run Code Online (Sandbox Code Playgroud)

是我遵循的写作,使用gulp,这是有效的.

但我更愿意使用webpack而不是gulp任务.

tru*_*k18 16

我希望这可以帮助您找到想法,因为我们的项目还需要将webpack和ASP.NET MVC集成在一起.注意到这是我自己的提议,所以可能有更好的方法来做到这一点.以下是我们的工作.

检查Github上源代码

模块1

1.构建项目

我们将项目分为两个文件夹:Client和Server.这些文件夹将位于mvc5-angular-webpack文件夹中,此文件夹将提交到存储库

mvc5-angular-webpack/
??? Server/
?   ??? WebApplication/
?   ?     ??? Controllers/
?   ?     ??? Scripts/
?   ?     ??? Web.config
?   ?     ??? Many more folder and file...
?   ?        
?   ??? Web-Core.sln
?   
??? Client/
    ??? modules
    ?     ??? angularModule-1/
    ?     ?      ??? main.ts
    ?     ?      ??? app.modules.ts
    ?     ?      ??? app.component.ts
    ?     ?      ??? Many more file...
    ?     ?
    ?     ??? angularModule-2/
    ?     ?      ??? main.ts
    ?     ?      ??? app.modules.ts
    ?     ?      ??? app.component.ts
    ?     ?      ??? Many more file...
    ?     ??? polyfill.ts
    ?     ??? vendor.ts
    ?
    ??? build.bat
    ??? npm-shrinkwrap.json
    ??? package.json
    ??? tsconfig.json
    ??? tslint.json
    ??? webpack.config.js
Run Code Online (Sandbox Code Playgroud)
  • Server文件夹中,我们添加了名为MVC的解决方案Web-Core.sln ,所有公共库项目都是用C#编写的.
  • Client文件夹中只包含前端相关的东西.要构建前端项目,只需调用build.bat.我稍后会讨论这个文件内容.在modules模块文件夹中,我们的项目将为每个模块创建每个子文件夹.

我们的网站有一些模块仍在使用纯Razor的服务器端渲染.并且有一些用AngularJS和Angular在客户端代码中编写的模块.

2.配置 webpack

假设您已经配置了所有typescriptnpm已经.让我们看看里面有什么webpack.config.js

const webpack = require('webpack')
const path = require('path')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const entryPath = path.resolve(__dirname, 'modules')
const corePath = path.resolve(__dirname, '../Server/WebApplication/Scripts/ng2')
const module1 = `${entryPath}/angularModule-1`
const module2 = `${entryPath}/angularModule-2`

module.exports = (envOptions) => {
    envOptions = envOptions || {};

    const config = {
        entry: {
            'polyfills': `${entryPath}/polyfill.ts`,
            'vendors': `${entryPath}/vendor.ts`,
            'module1': `${module1}/main.ts`,
            'module2': `${module2}/main.ts`            
        },
        output: {
            path: corePath,
            filename: '[name].js',
            sourceMapFilename: "[name].js.map"            
        },
        resolve: {
            extensions: ['.ts', '.js', '.html']
        },
        module: {
            rules: [
                {
                    test: /\.ts$/,
                    loaders: ['awesome-typescript-loader', 'angular2-template-loader']
                },
                {
                    test: /\.html$/,
                    loader: 'raw-loader'
                },
                {
                    test: /\.css$/,
                    loader: 'raw-loader'
                }
            ]
        },
        devtool: 'source-map',
        plugins: [
            new webpack.NoEmitOnErrorsPlugin(),
            new webpack.optimize.CommonsChunkPlugin({
                name: ['vendors', 'polyfills']
            })
        ]
    }

    if (envOptions.MODE === 'prod') {
        config.plugins.push(
            new UglifyJsPlugin()
        )
    }

    return config;
}
Run Code Online (Sandbox Code Playgroud)

所以基本上它会尝试解析上层的目录,并将所有编译的文件放在Server文件夹中的Scripts/ng2中.

3.配置npm脚本

配置完成后webpack,我们基本上会在构建过程中添加一些脚本来运行.将以下代码添加到package.json文件中

"scripts": {
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "dev": "webpack-dev-server --https --open",
    "watch": "webpack --config webpack.config.js --watch",
    "build": "webpack --config webpack.config.js",
    "build:html": "webpack --config webpack-html-plugin.config.js --env.MODE=prod",
    "build:prod": "webpack --config webpack.config.js --env.MODE=prod"    
}
Run Code Online (Sandbox Code Playgroud)

4.配置 build.bat

在Angular 2集成开始时,我们创建了一个用于前端目的的空Web应用程序项目,并将此项目添加为我们的依赖项WebApplication.但我们的后端团队后来抱怨前端流程的速度有多慢.因为每次构建时都不需要构建前端项目WebApplication.

build.bat文件的想法是手动运行它以在其机器上获得最新版本的前端代码.不是每次他们都运行项目.

call npm install --production  --loglevel verbose
echo "Build Angular projects"
npm run build:prod
Run Code Online (Sandbox Code Playgroud)

call是继续,因为一些命令中止命令行.请参考这里

这里的脚本非常简单.首先,我们运行npm install来恢复所有必要的依赖项.然后build:prod按我们package.json之前的定义调用.Webpack将把我们的Typescript代码捆绑成三个大的JavaScript文件vendors.js,polyfills.jsmodule1.js.

我们的团队使用Jenkins进行部署,所以我们的开发人员只需要包含运行build.bat,我们都已经完成了.如果要在每次构建项目时运行它,可以在预构建或后构建事件中进行设置.

预构建和后构建 图像来源

5.在视图中引用已编译的JavaScript文件.

通常我们只返回一个区域中的一个视图,如下所示.这my-angular-app就是我们所定义的app.component.ts

Index.cshtml

<script src="~/Scripts/ng2/polyfills.js"></script>
<script src="~/Scripts/ng2/vendors.js"></script>
<script src="~/Scripts/ng2/module1.js"></script>

<my-angular-app>
    Loading...
</my-angular-app>
Run Code Online (Sandbox Code Playgroud)

HomeController.cs

public ActionResult Module1()
{
    return View();
}
Run Code Online (Sandbox Code Playgroud)

如果我们部署到生产,这有点缺点.因为在编译的JavaScript更新之后,浏览器有时会因为缓存而保留旧版本的文件.我们应该有一种机制来在部署后为文件提供唯一的名称.我们有3种选择.

一世.HTML-的WebPack-插件

如果我们使用纯前端项目,请webpack提供html-webpack-plugin来处理它,如下所示.从技术上讲,它会使用唯一ID自动将JavaScript文件注入到我们的视图中.

的WebPack-HTML-的WebPack-plugin.config.js

...
const HtmlWebpackPlugin = require('html-webpack-plugin');
const viewPath = path.resolve(
    __dirname,
    "../Server/WebApplication/Views/Home"
  );
...
entry: {
    polyfills: `${entryPath}/polyfill.ts`,
    vendors: `${entryPath}/vendor.ts`,
    module1: `${module1}/main.ts`      
},
output: {
    path: corePath,
    filename: "[name].[hash].js",
    sourceMapFilename: "[name].[hash].js.map"
}
....
plugins: [,
    ...,
    new HtmlWebpackPlugin({
        template: viewPath + "/loader.cshtml",
        filename: viewPath + "/Module1.cshtml",
        inject: false
    })
]
Run Code Online (Sandbox Code Playgroud)

在与指定视图相同的文件夹中,我们创建了一个名为的cshtml文件 loader.cshtml

loader.cshtml

<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>  
    <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>  
<% } %> 

<my-angular-app>
    Loading...
</my-angular-app>
Run Code Online (Sandbox Code Playgroud)

npm run build:html按照定义运行package.json.如果它成功运行,结果将如此.

构建html插件

网络HTML插件

@{
    ViewBag.Title = "Module 1";
}
<script src="../../Scripts/ng2/vendors.1470de344a0f2260b700.js"></script>
<script src="../../Scripts/ng2/vendors.1470de344a0f2260b700.js"></script>
<script src="../../Scripts/ng2/module1.1470de344a0f2260b700.js"></script>

<my-angular-app>Loading....</my-angular-app>
Run Code Online (Sandbox Code Playgroud)

II.定义了您自己的JavaScript版本

在我们的ASP.NET MVC项目中有点不同,因为我们使用了多个Angular应用程序.因此,我们在类中定义了一个版本,并在加载JS时将其附加到文件的末尾.通过这样做,我们将确保将最新的内容加载到浏览器中.但它不属于这个问题,所以我不会再进一步​​了.基本上,它看起来像下面的代码.

<script src="@string.Format("{0}?v={1}", "~/Scripts/ng2/polyfills.js", VersionHelper.CurrentVersion())</script>
<script src="@string.Format("{0}?v={1}", "~/Scripts/ng2/vendors.js", VersionHelper.CurrentVersion())</script>
<script src="@string.Format("{0}?v={1}", "~/Scripts/ng2/module1.js", VersionHelper.CurrentVersion())</script>
Run Code Online (Sandbox Code Playgroud)

在浏览器上提供它时,它看起来像

<script src="~/Scripts/ng2/polyfills.js?v=1.1.0"></script>
<script src="~/Scripts/ng2/vendors.js?v=1.1.0"></script>
<script src="~/Scripts/ng2/module1.js?v=1.1.0"></script>
Run Code Online (Sandbox Code Playgroud)

III.ASP.NET捆绑

在Zyllem,我们的团队没有使用它,因为我们的JavaScript文件在模型内部配置并稍后将其呈现给视图.

您可以App_Start\BundleConfig.cs在项目中打开并配置一个包.让我们说名字是module1

bundles.Add(new ScriptBundle("~/bundles/module1").Include(
                "~/Scripts/ng2/polyfills.js",
                "~/Scripts/ng2/vendors.js"
                "~/Scripts/ng2/module1.js"));
Run Code Online (Sandbox Code Playgroud)

通过这样做在视图内部渲染.

Index.cshtml

@Scripts.Render("~/bundles/module1")
Run Code Online (Sandbox Code Playgroud)

因此,当在浏览器上提供服务时,它将在末尾具有唯一标记,并且它是不同的如果您在脚本包中进行任何更改.

<script src="/bundles/module1?v=2PbUw0z_gh_Ocp_Vz13rdmmBSG6utLJAXm2lThxYAow1"></script>
Run Code Online (Sandbox Code Playgroud)

如果一切正常,您将看到以下屏幕截图.

模块1

模块2


更新

在Github上添加存储库https://github.com/trungk18/mvc5-angular-webpack

  • 希望现在还为时不晚,我刚刚创建了一个存储库https://github.com/trungk18/mvc5-angular-webpack.你可以下载并试试.它也可以更容易. (2认同)
  • @trungk18 嘿,我真的很想把这个赏金奖励给你,因为你非常值得。我会努力做到这一点。我不明白为什么这些书呆子会搁置我的问题,因为这个答案非常有价值,很多人都可以从中受益。 (2认同)