2015-11-20 11 views
9

Ich habe eine "mittlere" Typescript-Anwendung (wie in, nicht trivial, aber auch keine Enterprise-Level, viele tausend Zeilen) mit Abhängigkeiten von jQuery, React und SocketIO - unter andere kleinere Bibliotheken.Leistungsprobleme mit Browserify + Watchify + Tsify + Schluck

Mein aktueller gulpfile ist dies:

var gulp = require("gulp"), 
    $ = require("gulp-load-plugins")(), 
    _ = require("lodash"), 
    tsify = require("tsify"), 
    browserify = require("browserify"), 
    source = require("vinyl-source-stream"), 
    debowerify = require("debowerify"), 
    watchify = require("watchify"), 
    lr = require("tiny-lr"), 
    buffer = require("vinyl-buffer"); 

var lrServer = lr(); 

var config = { 
    scripts: { 
     base: __dirname + "/Resources/Scripts", 
     main: "Application.ts", 
     output: "App.js" 
    }, 

    styles: { 
     base: __dirname + "/Resources/Styles", 
     sheets: ["Application.less", "Preload.less"], 
     autoprefixer: ["last 2 version", "safari 5", "ie 8", "ie 9", "opera 12.1", "ios 6", "android 4"] 
    }, 

    publicPath: __dirname + "/wwwroot" 
}; 

function printError(err) { 
    $.util.log($.util.colors.red.bold(err.type + " " + err.name + ":"), $.util.colors.white(err.message)); 
    this.emit("end"); 
} 

function buildScripts(watch, debug) { 
    var bundler = browserify({ 
      basedir: config.scripts.base, 
      debug: false, 
      entries: [config.scripts.base + "/" + config.scripts.main], 
      cache: {}, 
      packageCache: {} 
     }) 
     .plugin(tsify, { 
      module: "commonjs", 
      target: "es5", 
      jsx: "react" 
     }) 
     .transform(debowerify); 

    function build() { 
     return bundler.bundle() 
      .on("error", printError) 
      .pipe(source(config.scripts.output)) 
      .pipe($.if(!debug, buffer())) 
      .pipe($.if(!debug, $.uglify())) 
      .pipe(gulp.dest(config.publicPath + "/" + "scripts")); 
    } 

    if (!watch) 
     return build(); 

    bundler 
     .plugin(watchify) 
     .on("update", function() { 
      $.util.log($.util.colors.grey("Building scripts...")); 
      build(); 
     }) 
     .on("time", function (timeMs) { 
      $.util.log(
       $.util.colors.grey("Finished"), 
       $.util.colors.cyan("'dev.scripts.watch' after"), 
       $.util.colors.magenta(timeMs.toLocaleString() + " ms")); 
     }); 

    return build(); 
} 

gulp.task("prod.scripts", function() { 
    return buildScripts(false, false); 
}); 

gulp.task("dev.scripts", function() { 
    return buildScripts(false, true); 
}); 

gulp.task("dev.scripts.watch", function() { 
    return buildScripts(true, true); 
}); 

gulp.task("prod.styles", function() { 
    return gulp 
     .src(_.map(config.styles.sheets, function (sheet) { return config.styles.base + "/" + sheet; })) 
     .pipe($.less()) 
     .on("error", printError) 
     .pipe($.autoprefixer(config.styles.autoprefixer)) 
     .pipe($.uglifycss()) 
     .pipe(gulp.dest(config.publicPath + "/styles/")); 
}); 

gulp.task("dev.styles", function() { 
    return gulp 
     .src(_.map(config.styles.sheets, function (sheet) { return config.styles.base + "/" + sheet; })) 
     .pipe($.sourcemaps.init()) 
     .pipe($.less()) 
     .on("error", printError) 
     .pipe($.autoprefixer(config.styles.autoprefixer)) 
     .pipe($.sourcemaps.write()) 
     .pipe(gulp.dest(config.publicPath + "/styles/")); 
}); 

gulp.task("dev.styles.watch", ["dev.styles"], function() { 
    return gulp.watch(config.styles.base + "/**/*.{css,less}", ["dev.styles"]); 
}); 

gulp.task("dev.watch", ["dev.scripts.watch", "dev.styles.watch"], function() { 
    lrServer.listen(35729); 

    gulp.watch(config.publicPath + "/styles/**").on("change", function(file) { 
     lrServer.changed({ body: { files: [file.path] } }); 
    }); 
}); 

gulp.task("dev", ["dev.styles", "dev.scripts"]); 
gulp.task("prod", ["prod.styles", "prod.scripts"]); 

Alles funktioniert wie erwartet, aber die Bauzeiten, wenn die Uhr Aufgabe mit nehmen viele Sekunden. Das Seltsame ist, dass meine Aufgabe meldet, dass die Neukompilierung der Skripte in weniger als 500 ms (der Event-Handler beim "time" -Ereignis) stattfindet, aber wenn ich in meinem Kopf zähle, wird es erst drei bis vier Sekunden später beendet .

Beachten Sie, dass ich vor dem Einfügen meines vorhandenen TypeScript-Codes jQuery, React, Moment und die anderen Bibliotheken, die ich sehr schnell verwendete, geladen/gebündelt habe. Aus diesem Grund glaube ich nicht, dass die Verwendung eines separaten Anbieterpakets etwas beschleunigen würde. Auch das Ausgeben von Quellkarten wirkt sich nicht auf die Leistung aus.

Bevor ich zu browserify wechselte, verwendete ich gulp-typescript für die Kompilierung und requiredjs zum Modulladen. Diese Builds dauerten weniger als eine Sekunde. Requirejs verursachte jedoch aus anderen Gründen Probleme - und so oder so möchte ich von AMD zu CommonJS wechseln.

Für jetzt ist es keine riesige Sorge, aber wie das Projekt wächst, könnte es sicherlich Probleme mit meinem Entwicklungsablauf verursachen. Bei einem Projekt, das nur so groß ist, wie lange dauert es noch, etwas Größeres zu verarbeiten?

Darüber hinaus verursacht es auch Probleme mit Visual Studio. Dies ist eine ASP.NET 5-Anwendung und Visual Studio anscheinend besteht auf beim erneuten Laden/erneutes Parsen der gebündelten JavaScript-Datei jedes Mal, wenn es ändert, verursacht eine Verzögerung in der IDE für 1-2 Sekunden nach jeder Änderung: oben der 3-4 Sekunden dauert es für die Neukompilierung selbst. Das Skript wird in meinem Ordner "wwwroot" gerendert, und es scheint keine Möglichkeit zu geben, den Unterordner "scripts" mit den ASP.NET 5-Tools "auszuschließen".

Ich weiß, dass ich irgendwo etwas vermisse. Ein mögliches Problem ist, dass Tsify nicht die "Projekt" -Funktion des Typoskripts verwendet, um das Neuladen zu implementieren, was dazu führt, dass der TypeScript-Compiler jede Datei für jede Änderung neu verarbeitet.

Wie auch immer, ich kann nicht die einzige Person sein, die diese Tools über Spielzeugprojekte hinaus verwendet, also frage ich hier, ob jemand eine bessere Lösung hat; Seither läuft alles sehr gut.

EDIT --------------------------------

OK, werde ich meine eigenen Worte essen . Builds sind jetzt auf ungefähr eine Sekunde reduziert, da ich meine Drittanbieter-Bibliotheken in einem eigenen Bundle bündle. Hier ist meine aktualisierte gulpfile (man beachte die neue dev.scripts.vendor Aufgabe und den .Externes Aufruf in der buildScripts Funktion)

var gulp = require("gulp"), 
    $ = require("gulp-load-plugins")(), 
    _ = require("lodash"), 
    tsify = require("tsify"), 
    browserify = require("browserify"), 
    source = require("vinyl-source-stream"), 
    debowerify = require("debowerify"), 
    watchify = require("watchify"), 
    lr = require("tiny-lr"), 
    buffer = require("vinyl-buffer"); 

var lrServer = lr(); 

var config = { 
    scripts: { 
     base: __dirname + "/Resources/Scripts", 
     main: "Application.ts", 
     output: "App.js", 
     vendor: ["react", "jquery", "moment", "socket.io-client", "lodash", "react-dom"] 
    }, 

    styles: { 
     base: __dirname + "/Resources/Styles", 
     sheets: ["Application.less", "Preload.less"], 
     autoprefixer: ["last 2 version", "safari 5", "ie 8", "ie 9", "opera 12.1", "ios 6", "android 4"] 
    }, 

    publicPath: __dirname + "/wwwroot" 
}; 

function printError(err) { 
    $.util.log($.util.colors.red.bold(err.type + " " + err.name + ":"), $.util.colors.white(err.message)); 
    this.emit("end"); 
} 

function buildScripts(watch, debug) { 
    var bundler = browserify({ 
      basedir: config.scripts.base, 
      debug: false, 
      entries: [config.scripts.base + "/" + config.scripts.main], 
      cache: {}, 
      packageCache: {} 
     }) 
     .plugin(tsify, { 
      module: "commonjs", 
      target: "es5", 
      jsx: "react" 
     }); 

    if (debug) 
     bundler.external(config.scripts.vendor); 

    function build() { 
     return bundler.bundle() 
      .on("error", printError) 
      .pipe(source(config.scripts.output)) 
      .pipe($.if(!debug, buffer())) 
      .pipe($.if(!debug, $.uglify())) 
      .pipe(gulp.dest(config.publicPath + "/" + "scripts")); 
    } 

    if (!watch) 
     return build(); 

    bundler 
     .plugin(watchify) 
     .on("update", function() { 
      $.util.log($.util.colors.grey("Building scripts...")); 
      build(); 
     }) 
     .on("time", function (timeMs) { 
      $.util.log(
       $.util.colors.grey("Finished"), 
       $.util.colors.cyan("'dev.scripts.watch' after"), 
       $.util.colors.magenta(timeMs.toLocaleString() + " ms")); 
     }); 

    return build(); 
} 

gulp.task("prod.scripts", function() { 
    return buildScripts(false, false); 
}); 

gulp.task("dev.scripts", ["dev.scripts.vendor"], function() { 
    return buildScripts(false, true); 
}); 

gulp.task("dev.scripts.vendor", function() { 
    return browserify({ 
      debug: true, 
      cache: {}, 
      packageCache: {}, 
      require: config.scripts.vendor 
     }) 
     .bundle() 
     .on("error", printError) 
     .pipe(source("Vendor.js")) 
     .pipe(gulp.dest(config.publicPath + "/" + "scripts")); 
}); 

gulp.task("dev.scripts.watch", ["dev.scripts.vendor"], function() { 
    return buildScripts(true, true); 
}); 

gulp.task("prod.styles", function() { 
    return gulp 
     .src(_.map(config.styles.sheets, function (sheet) { return config.styles.base + "/" + sheet; })) 
     .pipe($.less()) 
     .on("error", printError) 
     .pipe($.autoprefixer(config.styles.autoprefixer)) 
     .pipe($.uglifycss()) 
     .pipe(gulp.dest(config.publicPath + "/styles/")); 
}); 

gulp.task("dev.styles", function() { 
    return gulp 
     .src(_.map(config.styles.sheets, function (sheet) { return config.styles.base + "/" + sheet; })) 
     .pipe($.sourcemaps.init()) 
     .pipe($.less()) 
     .on("error", printError) 
     .pipe($.autoprefixer(config.styles.autoprefixer)) 
     .pipe($.sourcemaps.write()) 
     .pipe(gulp.dest(config.publicPath + "/styles/")); 
}); 

gulp.task("dev.styles.watch", ["dev.styles"], function() { 
    return gulp.watch(config.styles.base + "/**/*.{css,less}", ["dev.styles"]); 
}); 

gulp.task("dev.watch", ["dev.scripts.watch", "dev.styles.watch"], function() { 
    lrServer.listen(35729); 

    gulp.watch(config.publicPath + "/styles/**").on("change", function(file) { 
     lrServer.changed({ body: { files: [file.path] } }); 
    }); 
}); 

gulp.task("dev", ["dev.styles", "dev.scripts"]); 
gulp.task("prod", ["prod.styles", "prod.scripts"]); 

Aber ich bin immer noch ein seltsames Problem bekommen. Da die Quellkarten deaktiviert sind (was sich jetzt anscheinend so schnell bemerkbar macht), meldet mein on ("time",() => {}) Callback 60-80ms für jede Dateiänderung, bleibt aber für etwa eine Sekunde hängen . Eine Sekunde ist über alles, was ich darauf warten möchte, also bin ich wieder besorgt, dass mit dem Wachstum des Projekts auch diese Wartezeit wachsen könnte.

Es wäre interessant zu sehen, wofür diese zusätzliche Sekunde der Zeit verwendet wird, wenn die Veranstaltung etwas viel kleineres berichtet.Vielleicht fange ich an, ein wenig nach der Quelle zu suchen, da es aussieht, als hätte niemand sofort die Antwort.

EINE ANDERE AUSGABE Dies ist nur eine Nebenbemerkung, aber debowerify funktioniert nicht mehr damit. Wenn Sie debowerify + bower verwenden, wird das erforderliche Modul in der endgültigen Ausgabe weiter gerendert, selbst wenn dieses Modul in der "externen" Liste aufgeführt ist. Zurzeit kann ich mit diesem Setup nur npm-Module verwenden, es sei denn, ich bin OK, wenn ich meinem App-Bundle mehr Kompilierungszeit hinzufüge.

Außerdem habe ich gelernt, dass debowerify npm-Module überschreiben wird, und dass es auf der Verzeichnisliste von bower_components basiert, NICHT auf Ihrer bower-Konfigurationsdatei. Ich hatte jQuery in npm installiert und bootstrap nur in bower; Da Bootstrap jedoch jQuery als Abhängigkeit herunterzog, wurde das Bower-jQuery-Modul bevorzugt über den NPM-jQuery geladen. Nur ein Kopf für Leute.

+1

nur einen Gedanken: Diese im Wesentlichen eine Profilierung Aufgabe. Was ist mit dem Hinzufügen von 'var debug = require ('gulp-debug');' und '.pipe (debug ({title: 'your message:'}))' 'um herauszufinden, welche Teile langsam sind? Ich bin überrascht, dass Quellkarten nicht langsam sind, verlangsamte einen Build-Prozess auf meinem Computer erheblich. Wir verwenden gulp-typescript und die Erstkompilierung dauert bis zu 10 Sekunden, aber dann ist die inkrementelle Kompilierung nur bis zu 1,5 Sekunden lang, was ziemlich komfortabel ist. –

+0

In unserem großen Projekt verwenden wir ASP.NET 4 und Typescript wird von Visual Studio 2015 kompiliert. Es dauert bis 1s zu kompilieren und es ist völlig in Ordnung. Als ich versucht habe, mit ASP.NET 5 zu spielen, scheint es, als wäre es immer noch sehr fehlerhaft, wenn man Typescript benutzt. –

+0

@MartinVseticka: Der bundler.bundle() startet den Stream, also kann ich nichts davor setzen. Es scheint jedoch, dass die bundler.bundle() -Operation für die zusätzliche Zeit verantwortlich ist. Außerdem ist Schluck-Typoskript * schnell *, aber da ich browserify für das Laden von Modulen verwende, kann ich es nicht verwenden. Was benutzt ihr zum Modulladen? – nlaq

Antwort

2

dies vergisst, nur neuesten TS verwenden + webpack :)

+0

Ich stimme zu, ich habe aufgehört, browserify vollständig zugunsten von Webpack zu verwenden. – nlaq