将Angular和Webpack集成到ASP.NET MVC应用程序中 [英] Integrate Angular and Webpack in an ASP.NET MVC Application

查看:75
本文介绍了将Angular和Webpack集成到ASP.NET MVC应用程序中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个编写步骤的文章,可以按照以下步骤将Angular添加到解决方案范围内的现有MVC应用程序中.我发现了一篇文章,向我展示了如何使用gulp.js文件添加角度,该文件提取必要的node_modules并将我的ts文件转换为js文件.我想使用webpack做同样的事情.

I am looking for a write up with steps i can follow to add Angular to an existing MVC application that lives in an area of my solution. I have found a write up that shows me how to add angular using a gulp.js file that pulls the necessary node_modules and transpiles my ts files into js files. I would like to do the same exact thing using webpack instead.

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

Currently my package.json looks like this.

{
    "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"
    }
}

是我遵循的使用gulp的文章,并且有效.

This is the write up I followed that uses gulp and this works.

但是我宁愿使用webpack代替gulp任务.

But i would much rather prefer using webpack instead of a gulp task.

推荐答案

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

I hope that can help you find the idea because our projects also need to integrate webpack and ASP.NET MVC together. Noted that it is my own proposal so that there might be a better way to do it. Below is what we do.

在Github上检查源代码

Check the source code on Github

1.构造项目

我们将项目分为两个文件夹:客户端和服务器.这些将位于 mvc5-angular-webpack 文件夹中,并且该文件夹将被提交到存储库中

We separated our project into two folders: Client and Server. Those will be located in mvc5-angular-webpack folder and this folder will be committed to the repository

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

  • Server 文件夹中,我们添加了名为Web-Core.sln 的MVC解决方案,并且所有公共库项目均使用C#编写.
  • 客户端文件夹中仅包含与前端相关的内容.要构建前端项目,只需调用build.bat.稍后我将讨论该文件的内容.在modules文件夹中,我们的项目将为每个模块创建每个子文件夹.
    • In the Server folder, we added the MVC solution named Web-Core.sln and all the common library project is written in C#.
    • In the Client folder only contains front-end related stuff. To build the front project, simply call the build.bat. I will talk about this file content later. Inside modules folder, our project will create each subfolder for each module.
    • 我们的网站上仍有一些模块仍使用纯Razor进行服务器端渲染.还有一些用AngularJS和Angular用客户端代码编写的模块.

      Our website has some module still using server-side rendering with pure Razor. And there is some module written in client-side code with AngularJS and Angular.

      2.配置webpack

      2. Configure webpack

      假定您已经配置了所有typescriptnpm.让我看看webpack.config.js

      Assume that you configured all the typescript and npm already. Let see what I have inside 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;
      }
      

      因此,基本上,它将尝试尝试在更高级别上解析目录,并将所有编译的文件放入 Server 文件夹中的 Scripts/ng2 .

      So basically it will try to resolve the directory in an upper level and put all the compiled files to Scripts/ng2 inside Server folder.

      3.配置npm脚本

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

      After configured webpack, we will basically add some more script to run during the build process. Add the following code to package.json file

      "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"    
      }
      

      4.配置build.bat

      4. Configure build.bat

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

      At the beginning of Angular 2 integration, we have created an empty web application project for front-end purpose and added this project as a dependency of our WebApplication. But our backend team later complained about how slow the front-end process take. Because they don't need the front-end project to build every time the WebApplication is being built.

      build.bat文件的想法是手动运行该文件,以在其计算机上获取最新版本的前端代码.他们并非每次都运行项目.

      The idea of the build.bat file is to manually run it to get the latest version of front-end code on their machine. Not every single time they run the project.

      call npm install --production  --loglevel verbose
      echo "Build Angular projects"
      npm run build:prod
      

      call将继续,因为某些命令将中止命令行.请在此处

      The call is to continue because some of the commands abort the command line. Refer here

      这里的脚本非常简单.首先,我们运行npm install恢复所有必要的依赖关系.然后调用我们之前在package.json上定义的build:prod. Webpack将负责将我们的Typescript代码打包为三个大的JavaScript文件,分别为vendors.jspolyfills.jsmodule1.js.

      The script here is very simple. First, we run the npm install to restore all the necessary dependency. Then call build:prod as we defined on package.json before. Webpack will take care of bundle our Typescript code into three big JavaScript files as vendors.js, polyfills.js and module1.js.

      我们的团队使用Jenkins进行部署,因此我们的开发人员只需要包括运行build.bat的内容,就可以完成工作.如果要在每次构建项目时都运行它,则可以在构建前或构建后事件中进行设置.

      Our team used Jenkins for deployment, so our dev ops just need to include to run the build.bat and we are all set. If you want to run it everytime your project was built, you can set it inside the pre-build or post-build event.

      图片来源

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

      通常,我们将在下面的区域中仅返回一个视图. my-angular-app是我们在app.component.ts

      Normally we will return only one view in an area as below. The my-angular-app is what we defined in app.component.ts

      Index.cshtml

      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>
      

      HomeController.cs

      HomeController.cs

      public ActionResult Module1()
      {
          return View();
      }
      

      如果我们将其部署到生产环境,那将是一个缺点.因为在更新编译的JavaScript之后,由于缓存,浏览器有时仍会保留文件的旧版本.部署后,我们应该具有一种为文件提供唯一名称的机制.我们有3种选择.

      That is a bit drawback If we deploy to production. Because after the compiled JavaScript was updated, the browser sometimes still keep the old version of the file because of caching. We should have a mechanism to provide a unique name for the files after deployment. There are 3 options for us to do so.

      i. html-webpack-plugin

      i. html-webpack-plugin

      如果我们使用纯前端项目,则webpack提供 html-webpack-plugin 进行以下操作.从技术上讲,它将使用唯一的ID自动将JavaScript文件注入到我们的视图中.

      If we work with pure front-end project, webpack provides html-webpack-plugin to take care of it as below. Technically, It will automatically inject the JavaScript file into our view with the unique id.

      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
          })
      ]
      

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

      And in the same folder with the designated view, we created a cshtml file named 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>
      

      并按照package.json上的定义运行npm run build:html.如果成功运行,结果将如下所示.

      And run the npm run build:html as defined on package.json. If it runs successfully, the result will look like that.

      @{
          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>
      

      ii.定义了自己的JavaScript版本

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

      In our ASP.NET MVC project is a bit different because we used more than one Angular app. So that we defined a version in the class and append it at the end of the file when loading the JS. By doing it, we will make sure the latest will be loaded into the browser. But it is out of this question context so I will not go further. Basically, It is gonna look like below code.

      <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>
      

      在浏览器上投放时,它看起来像

      When serving it on browser, it will look like

      <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>
      

      iii. ASP.NET捆绑

      iii. ASP.NET Bundling

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

      At Zyllem, our team didn't use it because of our JavaScript files is configure inside the model and render it later to the view.

      您只需在项目中打开App_Start\BundleConfig.cs并配置捆绑软件即可.假设名称为module1

      You can just open App_Start\BundleConfig.cs in your project and config a bundle. Let say the name is module1

      bundles.Add(new ScriptBundle("~/bundles/module1").Include(
                      "~/Scripts/ng2/polyfills.js",
                      "~/Scripts/ng2/vendors.js"
                      "~/Scripts/ng2/module1.js"));
      

      然后在视图中进行渲染.

      And render inside the view by doing it.

      Index.cshtml

      Index.cshtml

      @Scripts.Render("~/bundles/module1")
      

      因此,当在浏览器中投放时,它的末尾将具有唯一令牌,并且如果您在脚本包中进行任何更改,则令牌会有所不同.

      So that when serving on the browser, it will have the unique token at the end and it is different If you make any changes in the script bundle.

      <script src="/bundles/module1?v=2PbUw0z_gh_Ocp_Vz13rdmmBSG6utLJAXm2lThxYAow1"></script>
      

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

      If everything works fine, you will see the below screenshots.

      更新

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

      Add the repository on Github https://github.com/trungk18/mvc5-angular-webpack

      这篇关于将Angular和Webpack集成到ASP.NET MVC应用程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆