شروع به کار با AngularJS 2.0 و TypeScript - قسمت دوازدهم - توزیع برنامه
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: هشت دقیقه

یکی از مشکلاتی را که حین کار با AngularJS 2.0 به کرات شاهدش خواهید بود، کش شدن تک اسکریپت‌های ماژول‌های آن است. برای مثال فایل ts ایی را تغییر می‌دهید؛ به فایل js معادل آن کامپایل می‌شود. چون برنامه ماژولار است و این ماژول پیشتر توسط مرورگر بارگذاری شده‌است، بار دیگر نسبت به دریافت مجدد آن اقدام نمی‌کند. همچنین با ارائه‌ی نگارش RC، دیگر خبری از فایل‌های bundle این مجموعه نیست و اینبار اگر تبادلات شبکه‌ی بین سرور و برنامه را مرور کنید، به چند صد رفت و برگشت، برای دریافت فایل‌های JS کتابخانه‌های مرتبط خواهید رسید که اصلا بهینه نیست. در این قسمت قصد داریم، یک Gulp Task را ایجاد کنیم تا تمام اسکریپت‌های موجود را با هم یکی کرده و توزیع برنامه را ساده‌تر کند؛ به همراه بالا رفتن سرعت کار با این سیستم، بدون نیازی به توزیع تک تک فایل‌های js نهایی، که شاید صدها فایل باشند.


نصب پیشنیازهای کار با Gulp و TypeScript

فایل package.json در قسمت اول این سری معرفی شد. دراینجا قسمت devDependencies آن‌را به نحو ذیل تکمیل کنید:
"devDependencies": {
        "typescript": "^1.8.10",
        "gulp": "^3.9.1",
        "path": "^0.12.7",
        "gulp-clean": "^0.3.2",
        "fs": "^0.0.2",
        "gulp-concat": "^2.6.0",
        "gulp-typescript": "^2.13.1",
        "gulp-tsc": "^1.1.5",
        "del": "^2.2.0",
        "gulp-autoprefixer": "^3.1.0",
        "gulp-cssnano": "^2.0.0",
        "gulp-html-replace": "^1.5.4",
        "gulp-htmlmin": "^1.0.5",
        "gulp-uglify": "^1.5.3",
        "merge-stream": "^1.0.0",
        "systemjs-builder": "^0.15.16",
        "typings": "^0.8.1"
    },
به این ترتیب، پس از ذخیره‌ی فایل و یا کلیک راست بر روی نام فایل و انتخاب گزینه‌ی restore packages، وابستگی‌هایی مانند gulp، gulp-typescript و یک سری فشرده ساز CSS و HTML دریافت خواهند شد.
نکته‌ی مهم آن systemjs-builder است. این کتابخانه کار کامپایل systemjs.config.js را به یک تک اسکریپت انجام می‌دهد. به این ترتیب مشکل صدها بار رفت و برگشت به سرور، برای دریافت وابستگی‌های AngularJS 2.0، به طور کامل برطرف می‌شود.


افزودن فایل gulpfile.js به پروژه

یا یک فایل جدید جاوا اسکریپتی را به نام gulpfile.js به ریشه‌ی پروژه اضافه کنید و یا از منوی project -> add new item نیز می‌توانید گزینه‌ی gulp configuration file را در VS 2015 انتخاب نمائید. محتوای این فایل را به نحو ذیل تغییر دهید:
var gulp = require("gulp"),
    concat = require("gulp-concat"),
    tsc = require("gulp-typescript"),
    jsMinify = require("gulp-uglify"),
    cssPrefixer = require("gulp-autoprefixer"),
    cssMinify = require("gulp-cssnano"),
    del = require("del"),
    merge = require("merge-stream"),
    minifyHTML = require('gulp-htmlmin'),
    SystemBuilder = require("systemjs-builder");
 
var appFolder = "./app";
var outFolder = "wwwroot";
 
gulp.task("clean", () => {
    return del(outFolder);
});
 
gulp.task("shims", () => {
    return gulp.src([
            "node_modules/es6-shim/es6-shim.js",
            "node_modules/zone.js/dist/zone.js",
            "node_modules/reflect-metadata/Reflect.js"
    ])
    .pipe(concat("shims.js"))
    .pipe(jsMinify())
    .pipe(gulp.dest(outFolder + "/js/"));
});
 
gulp.task("tsc", () => {
    var tsProject = tsc.createProject("./tsconfig.json");
    var tsResult = gulp.src([
         appFolder + "/**/*.ts"
    ])
    .pipe(tsc(tsProject), undefined, tsc.reporter.fullReporter());
 
    return tsResult.js.pipe(gulp.dest("build/"));
});
 
gulp.task("system-build", ["tsc"], () => {
    var builder = new SystemBuilder();
 
    return builder.loadConfig("systemjs.config.js")
        .then(() => builder.buildStatic(appFolder, outFolder + "/js/bundle.js"))
        .then(() => del("build"));
});
 
 
gulp.task("buildAndMinify", ["system-build"], () => {
    var bundle = gulp.src(outFolder + "/js/bundle.js")
        .pipe(jsMinify())
        .pipe(gulp.dest(outFolder + "/js/"));
 
    var css = gulp.src(outFolder + "/css/styles.css")
        .pipe(cssMinify())
        .pipe(gulp.dest(outFolder + "/css/"));
 
    return merge(bundle, css);
}); 
 
gulp.task("favicon", function () {
    return gulp.src("./app/favicon.ico")
      .pipe(gulp.dest(outFolder));
});
 
gulp.task("css", function () {
    return gulp.src(appFolder + "/**/*.css")
      .pipe(cssPrefixer())
      .pipe(cssMinify())
      .pipe(gulp.dest(outFolder));
});
 
gulp.task("templates", function () {
    return gulp.src(appFolder + "/**/*.html")
        .pipe(minifyHTML())
        .pipe(gulp.dest(outFolder));
});
 
gulp.task("assets", ["templates", "css", "favicon"], function () {
    return gulp.src(appFolder + "/**/*.png")
      .pipe(gulp.dest(outFolder));
}); 
 
gulp.task("otherScriptsAndStyles", () => {
    gulp.src([
            "jquery/dist/jquery.*js",
            "bootstrap/dist/js/bootstrap*.js"
    ], {
        cwd: "node_modules/**"
    })
    .pipe(gulp.dest(outFolder + "/js/"));
 
    gulp.src([
        "node_modules/bootstrap/dist/css/bootstrap.css"
    ]).pipe(cssMinify()).pipe(gulp.dest(outFolder + "/css/"));
 
    gulp.src([
        "node_modules/bootstrap/fonts/*.*"
    ]).pipe(gulp.dest(outFolder + "/fonts/"));
}); 
 
//gulp.task("watch.tsc", ["tsc"], function () {
//    return gulp.watch(appFolder + "/**/*.ts", ["tsc"]);
//});
 
//gulp.task("watch", ["watch.tsc"]); 
 
gulp.task("default", [
    "shims",
    "buildAndMinify",
    "assets",
    "otherScriptsAndStyles"
    //,"watch"
]);
توضیحات

در این فایل فرض شده‌است که خروجی نهایی برنامه قرار است در پوشه‌ای به نام wwwroot کپی شود و پوشه‌ی اصلی برنامه، همان پوشه‌ای به نام app، در ریشه‌ی پروژه است.
 var appFolder = "./app";
var outFolder = "wwwroot";
سپس در اینجا یک سری task کامپایل و کپی کردن فایل‌ها تهیه شده‌اند:
 1) وظیفه‌ی clean، کار تمیز کردن پوشه‌ی نهایی خروجی برنامه را انجام می‌دهد (حذف تمام فایل‌های آن).
 2) وظیفه‌ی shims، کار بسته بندی، یکی کردن و فشرده کردن سه اسکریپت es6-shim.js، zone.js و Reflect.js را انجام می‌دهد. سپس تک فایل حاصل را به نام shims.js، در پوشه‌ی wwwroot/js کپی می‌کند.
 3) وظیفه‌ی tsc، یکبار دیگر کامپایلر TypeScript را اجرا می‌کند تا مطمئن شویم با آخرین نگارش فایل‌های js برنامه کار می‌کنیم.
 4) وظیفه‌ی system-build، کار پردازش خودکار مداخل فایل systemjs.config.js را انجام می‌دهد. در آخرین نگارش ارائه شده‌ی AngularJS 2.0، بجای ذکر مداخل مورد نیاز آن، این  تک فایل systemjs.config.js را به صفحه پیوست می‌کنیم تا اسکریپت‌های لازم را (چند صد عدد)، به صورت خودکار بارگذاری کند. برای یکی کردن این چند صد عدد اسکریپت، از کتابخانه‌ی SystemBuilder  آن کمک گرفته و کار کامپایل نهایی را انجام می‌دهیم. خروجی تمام این فایل‌ها، به همراه کلیه فایل‌های js حاصل از کامپایل فایل‌های TypeScript برنامه، در فایلی به نام bundle.js کپی شده‌ی در پوشه‌ی wwwroot/js نوشته می‌شود. بنابراین دیگر نیازی نیست تا فایل‌های js پوشه‌ی app و همچنین فایل‌های js وابستگی‌های AngularJS 2.0 را توزیع کنیم. تک فایل bundle.js، حاوی تمام این‌ها است.
 5) وظیفه‌ی buildAndMinify کار اجرای وظیفه‌ی system-bulder را به همراه فشرده سازی تک فایل bundle.js، به عهده دارد. به علاوه اگر در پوشه‌ی css آن نیز فایل styles.css موجود باشد، آن را فشرده می‌کند.
 6) در ادامه یک سری وظیفه‌ی کپی کردن منابع برنامه را مشاهده می‌کنید. مانند favicon که کار کپی کردن این آیکن را به پوشه‌ی wwwroot انجام می‌دهد. وظیفه‌ی css، فایل‌های css موجود در پوشه‌های برنامه را به wwwroot و زیر پوشه‌های آن کپی می‌کند. وظیفه‌ی templates، کار کپی کردن فایل‌های html قالب‌های کامپوننت‌ها را بر عهده دارد. وظیفه‌ی assets، کار کپی کردن فایل‌های png را انجام می‌دهد.
 7) وظیفه‌ی otherScriptsAndStyles یک سری css و js ثالث را به پوشه‌ی wwwroot کپی می‌کند؛ مانند فایل‌های بوت استرپ و جی‌کوئری.
 8) وظیفه‌ی default، کار اجرای تمام این وظایف را با هم به عهده دارد.

اکنون اگر بر روی gulpfile.js کلیک راست کنید، گزینه‌ی task runner explorer ظاهر خواهد شد. آن‌را انتخاب کنید:


بر روی وظیفه‌ی default کلیک راست کرده و آن‌را اجرا کنید. پس از مدتی پوشه‌ی جدید wwwroot ساخته شده و فایل‌های نهایی برنامه به آن کپی می‌شوند.
 

اصلاح فایل index.html و یا Views\Shared\_Layout.cshtml

اکنون که تمام فایل‌های مورد نیاز پروژه در پوشه‌ی wwwroot کپی شده‌اند، نیاز است فایل index.html را به نحو ذیل تغییر داد:
<!DOCTYPE html>
<html>
<head>
    <base href="/">
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
 
    <link href="~/wwwroot/css/bootstrap.css" rel="stylesheet" />
    <link href="~/wwwroot/app.component.css" rel="stylesheet" />
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
 
    <script src="~/wwwroot/js/shims.js"></script>
</head>
 
<body>
    <div>
        @RenderBody()
        <pm-app>Loading App...</pm-app>
    </div>
 
    <script src="~/wwwroot/js/jquery/dist/jquery.min.js"></script>
    <script src="~/wwwroot/js/bootstrap/dist/js/bootstrap.min.js"></script>
    <script src="~/wwwroot/js/bundle.js"></script>
 
    @RenderSection("Scripts", required: false)
</body>
</html>
همانطور که مشاهده می‌کنید، اینبار دیگر خبری از systemjs.config.js و وابستگی‌های آن نیست.
اسکریپت‌های shims که برای مرورگرهای قدیمی‌تر درنظر گرفته شده‌اند، به تک فایل wwwroot/js/shims.js منتقل شده‌اند.
تمام اسکریپت‌های AngularJS 2.0 و وابستگی‌های آن به همراه تمام اسکریپت‌های برنامه‌ی خودمان، به تک فایل wwwroot/js/bundle.js منتقل شده‌اند.

اکنون اگر برنامه را اجرا کنید، سرعت آن با قبل قابل مقایسه نیست! اینبار دیگر نه نیازی به بارگذاری تمام وابستگی‌های AngularJS 2.0 به صورت مجزا توسط systemjs.config.js وجود دارد و نه به ازای مشاهده‌ی هر صفحه‌ای، یکبار قرار است فایل js کامپوننت آن بارگذاری شود. تمام این‌ها داخل فایل wwwroot/js/bundle.js قرار گرفته‌اند و تنها یکبار بارگذاری می‌شوند.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MVC5Angular2.part12.zip


خلاصه‌ی بحث

با نوشتن یک Gulp Task جدید می‌توان بر اساس فایل systemjs.config.js، تمام اسکریپت‌های دخیل در اجرای برنامه را به صورت خودکار یافته و به صورت یک تک فایل نهایی، بسته بندی و توزیع کرد.
  • #
    ‫۸ سال و ۴ ماه قبل، پنجشنبه ۲۳ اردیبهشت ۱۳۹۵، ساعت ۱۷:۵۱
    یک نکته‌ی تکمیلی

    روش توصیه‌ی شده‌ی توسط تیم AngularJS 2.0، جهت توزیع برنامه‌ها به این صورت است:
     1) ابتدا برنامه‌ی جدید angular-cli را نصب کنید: (بدیهی است پیش از آن باید وابستگی‌های Nodejs بر روی سیستم شما نصب باشند)
    npm install -g angular-cli
     2) با دستور ذیل، یک برنامه‌ی جدید AngularJS 2.0 را به همراه تمام وابستگی‌های آن، می‌توانید آغاز کنید:
    ng new AngularCLIDemoApp
    ابتدا به پوشه‌ی مدنظر وارد شده و سپس در خط فرمان، دستور فوق را وارد کنید. به این ترتیب ساختار یک برنامه‌ی جدید AngularJS 2.0 را خواهید داشت.
     3) اکنون اگر دستور ذیل را صادر کنید:
     ng build -prod
    به صورت خودکار، کار بسته بندی و توزیع نهایی برنامه، در پوشه‌ای به نام dist، انجام خواهد شد.

    دو مطلب تکمیلی
    Angular CLI is here for AngularJS 2  
    Angular 2 CLI – Build Angular 2 apps using Command Line Interface  
  • #
    ‫۸ سال و ۴ ماه قبل، شنبه ۲۵ اردیبهشت ۱۳۹۵، ساعت ۱۴:۴۳
    یک نکته‌ی تکمیلی

    به مستندات رسمی AngularJS 2.0، فصل جدیدی به نام «Introduction to Webpack» اضافه شده‌است. در اینجا می‌توان Webpack را جایگزین Gulp کرد و نکته‌ی جالب آن، امکان نوشتن یک چنین کامپوننت‌هایی هستند:
    import { Component } from '@angular/core';
    import '../../public/css/styles.css';
    
    @Component({
          selector: 'my-app',
          template: require('./app.component.html'),
          styles: [require('./app.component.css')]
    })
    export class AppComponent { }
    در اینجا معرفی template و css جداگانه‌ی تعریف شده‌ی در فایل‌های مجزای خودشان، توسط متد require مربوط به webpack انجام شده‌اند. مزیت آن این است که زمانیکه webpack کار bundling برنامه را انجام می‌دهد، تک فایل js حاصل، حاوی تمام فایل‌های html و css برنامه هم خواهد بود و دیگر نیازی به توزیع جداگانه‌ی آن‌ها نیست. به عبارتی شما در حین تهیه‌ی برنامه، inline کار نمی‌کنید، اما webpack آن‌ها را حین توزیع نهایی، به صورت خودکار تبدیل به قالب‌ها و شیوه‌نامه‌های inline می‌کند.
    • #
      ‫۸ سال و ۴ ماه قبل، یکشنبه ۲۶ اردیبهشت ۱۳۹۵، ساعت ۱۹:۱۲
      روش فعال سازی متد require به این صورت است:
      الف) نیاز است typings مربوط به nodejs اضافه شود؛ جهت شناسایی متد require و همچنین شیء process در فایل main.ts جدید. بنابراین باید فایل typings.json جهت افزودن سطر جدید node، ویرایش شود:
      {
          "ambientDependencies": {
              "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
              "jasmine": "registry:dt/jasmine#2.2.0+20160412134438",
              "node": "registry:dt/node#4.0.0+20160509154515"
          }
      }
      با ذخیره سازی فایل package.json مداخل فوق اضافه خواهند شد.

      ب) اینبار فایل main.ts چنین شکلی را پیدا می‌کند:
      /// <reference path="../typings/browser/ambient/es6-shim/index.d.ts" />
      /// <reference path="../typings/browser/ambient/node/index.d.ts" /> 
       
      import { bootstrap } from '@angular/platform-browser-dynamic';
      import { enableProdMode } from '@angular/core';
       
      // Our main component
      import { AppComponent } from "./app.component";
       
      if (process.env.ENV === "production") {
          enableProdMode();
      }
       
      bootstrap(AppComponent, []);
      در اینجا ذکر ambient/node/index.d.ts به همراه import و اجرای متد enableProdMode، جدید هستند.

      ج) مداخل تعاریف قالب‌ها و شیوه نامه‌ها، به صورت زیر اصلاح می‌شوند و مسیر آن‌ها باید به نحو ذیل مقدار دهی شود (از ابتدای پوشه‌ی جاری):
      @Component({
          selector: 'pm-products',
          //templateUrl: 'app/products/product-list.component.html',
          template: require('./product-list.component.html'),
          //styleUrls: ['app/products/product-list.component.css'],
          styles: [require('./product-list.component.css')],
          pipes: [ProductFilterPipe],
          directives: [StarComponent, ROUTER_DIRECTIVES]
      })
  • #
    ‫۸ سال و ۴ ماه قبل، چهارشنبه ۵ خرداد ۱۳۹۵، ساعت ۲۰:۱۵
    یک نکته‌ی تکمیلی
    مزیت استفاده از روش webpack، امکان تعریف یک چنین آدرس دهی‌هایی است جهت یکی کردن فایل‌های html با فایل bundle نهایی:
    template: require('./app.component.html'),
    برای gulp هم افزونه‌ای به نام «gulp-angular-embed-templates» وجود دارد که چنین کاری را انجام می‌دهد (بدون نیاز به استفاده از متد require به صورت فوق). برای فایل‌های CSS هم از افزونه‌ی «gulp-angular2-embed-sass » می‌توان استفاده کرد.
    در این حالت وظیفه‌ی tsc به شکل زیر درخواهد آمد:
    var embedTemplates = require('gulp-angular-embed-templates');
    
    gulp.task("tsc", () => {
        var tsProject = tsc.createProject("./tsconfig.json");
        var tsResult = gulp.src([appFolder + "/**/*.ts"])
        .pipe(embedTemplates({
            debug: true,
            basePath: "./",
            sourceType: "ts",
            minimize: {
                empty: true,
                spare: true,
                quotes: true,
                dom: {
                    xmlMode: true,
                    lowerCaseAttributeNames: false,
                    lowerCaseTags: false
                }
            }
        })) // inline templates
        .pipe(tsc(tsProject), undefined, tsc.reporter.fullReporter());
    
        return tsResult.js.pipe(gulp.dest(appFolder));
    });
    و دیگر نیازی به وظیفه‌ی templates نیست.
    • #
      ‫۷ سال و ۱۱ ماه قبل، یکشنبه ۱۸ مهر ۱۳۹۵، ساعت ۱۷:۱۲
      با سلام و تشکر
      من طبق این آموزش تنظیمات webpack را در پروژه ام انجام داده ام. از angular2 rc5 استفاده کرده ام. آخرین ورژن nodejs (v6.7.0) و   typescript(2.0.3 ) نصب کردم
      فایل package.json به صورت زیر میباشد
      {
        "name": "mainmodule",
        "version": "1.0.0",
        "scripts": {
          "build": "webpack --progress",
          "build:prod": "webpack -p --progress",
          "serve": "webpack-dev-server --inline --progress ",
          "postinstall": "typings install"
        },
        "dependencies": {
          "@angular/common": "2.0.0-rc.5",
          "@angular/compiler": "2.0.0-rc.5",
          "@angular/core": "2.0.0-rc.5",
          "@angular/forms": "0.3.0",
          "@angular/http": "2.0.0-rc.5",
          "@angular/platform-browser": "2.0.0-rc.5",
          "@angular/platform-browser-dynamic": "2.0.0-rc.5",
          "@angular/router": "3.0.0-rc.1",
          "core-js": "^2.4.0",
          "reflect-metadata": "^0.1.3",
          "rxjs": "5.0.0-beta.6",
          "typings": "^1.4.0",
          "zone.js": "^0.6.12"
        },
        "devDependencies": {
          "html-webpack-plugin": "^2.22.0",
          "ts-loader": "^0.9.0",
          "typescript": "^2.0.3",
          "typings": "^1.4.0",
          "webpack": "^1.13.2",
          "webpack-dev-server": "^1.16.2"
      
        }
      }
      ولی با اجرای کدnpm run serve با خطای زیر مواجه میشوم


      با توجه به خطای connect ECONNREFUSED 10.10.34.36:443 که در زمان ذخیره package.json به دلیل وجود typings install رخ میداد از vpn استفاده کردم و ذخیره فایل درست انجام شد ولی بازهم با اجرای npm run serve خطای بالا رخ میدهد.
  • #
    ‫۸ سال و ۲ ماه قبل، جمعه ۲۵ تیر ۱۳۹۵، ساعت ۰۷:۱۵
    سلام؛ بعد از توزیع تمپلت‌های برنامه با گالپ تمامی دایرکتیوهای انگولارجی اس به حروف کوچک تبدیل می‌شوند.برای مثال ngFor* به ngfor* تبدیل میشه. وقتی مرحله مینی فای کردن تمپلت‌ها رو غیرفعال کردم مشکل حل شد!
    gulp.task("templates", function () {
        return gulp.src(appFolder + "/**/*.html")
            //.pipe(minifyHTML())
            .pipe(gulp.dest(outFolder + "/app"));
    });
    • #
      ‫۸ سال و ۲ ماه قبل، جمعه ۲۵ تیر ۱۳۹۵، ساعت ۱۱:۴۹
      از این پارامترها استفاده کنید:
      minifyHTML({
                  empty: true,
                  spare: true,
                  quotes: true,
                  dom: {
                      xmlMode: true,
                      lowerCaseAttributeNames: false,
                      lowerCaseTags: false
                  }
      })
  • #
    ‫۸ سال و ۱ ماه قبل، چهارشنبه ۱۳ مرداد ۱۳۹۵، ساعت ۱۴:۲۴
    var builder = new SystemBuilder();
        return builder.loadConfig("systemjs.config.js")
            .then(() => builder.buildStatic(appFolder, outFolder + "/js/bundle.js"))
            .then(() => del("build"));
    با سلام و عرض خسته نباشید،این قسمت از برنامه  در برنامه asp.net core کار نمیکند و پوشه wwwroot رو در نظر نمیگرد و فایل‌های مربوطه را پیدا نمیکند.
    راهی برای در نظر گرفتن پوشه  wwwroot  وجود دارد؟
    با تشکر
    • #
      ‫۸ سال و ۱ ماه قبل، چهارشنبه ۱۳ مرداد ۱۳۹۵، ساعت ۱۴:۵۵
      - در مورد تنظیمات سمت سرور AngularJS 2.0 در ASP.NET Core 1.0، در قسمت «معرفی بسته‌ی نیوگت Microsoft.AspNetCore.SpaServices» بحث شده‌است.
      - اما ... Gulp جاوا اسکریپتی اساسا وابستگی خاصی به فناوری‌های سمت سرور ندارد. در اینجا فقط نحوه‌ی مسیردهی این پوشه‌ها مهم هستند (و Task runner آن فقط به این مسایل دقت می‌کند):
      var appFolder = "./app";
      var outFolder = "wwwroot";
      در اینجا app/. به این معنا است که محل واقع شدن فایل تنظیمات gulp و همچنین فایل systemjs.config.js، یک سطح بالاتر هستند از پوشه‌ی app (جایی که قرار است فایل‌های اصلی از آن دریافت شوند) و همچنین پوشه‌ی wwwroot ذکر شده (جایی که قرار است فایل‌های نهایی کپی شوند):
      gulpfile.js
      systemjs.config.js
      --app
      --wwwroot
  • #
    ‫۸ سال و ۱ ماه قبل، چهارشنبه ۱۳ مرداد ۱۳۹۵، ساعت ۱۶:۴۰