Problemas de desempenho com o Browserify + Watchify + Tsify + Gulp

9

Eu tenho um aplicativo "medium" Typescript (como em, não trivial, mas não em nível corporativo, muitos milhares de linhas) com dependências em jQuery, React e SocketIO - entre outras bibliotecas menores.

Meu gulpfile atual é o seguinte:

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"]);

Tudo funciona conforme o esperado, no entanto, os tempos de compilação ao usar a tarefa de inspeção estão demorando muitos segundos. O curioso é que minha tarefa relata que a recompilação dos scripts aconteceu em menos de 500ms (o manipulador de eventos no evento "time"), mas se eu contar na minha cabeça, ele não termina até três a quatro segundos depois .

Note que antes de colar no meu código TypeScript existente, eu estava carregando / agrupando jQuery, React, Moment e as outras bibliotecas que eu estava usando muito rapidamente. Por causa disso, não acho que usar um pacote de fornecedores separado acelere qualquer coisa. Além disso, não escrever os sourcemaps também não afeta o desempenho.

Antes de mudar para o browserify, eu estava usando o gulp-typescript para compilação e requirejs para o carregamento do módulo. Essas construções levaram menos de um segundo. No entanto, requirejs estava causando problemas por outras razões - e de qualquer forma, eu quero me afastar da AMD para o CommonJS.

Por enquanto, não é uma preocupação enorme , mas à medida que o projeto cresce, certamente pode causar problemas no meu fluxo de desenvolvimento. Com um projeto tão grande, quanto tempo levará para processar algo maior?

Além disso, também está causando problemas com o Visual Studio. Este é um aplicativo ASP.NET 5, e o Visual Studio aparentemente insiste em carregar / repensar o arquivo JavaScript incluído toda vez que ele muda, causando um atraso no IDE por 1-2 segundos após cada mudança: em cima dos 3-4 segundos necessários para recompilação em si. O script está sendo renderizado para minha pasta wwwroot e parece não haver nenhuma maneira de "excluir" a subpasta de scripts com o conjunto de ferramentas do ASP.NET 5.

Eu sei que estou perdendo alguma coisa em algum lugar. Um possível problema é que o tsify não está usando o recurso "project" do typescript para implementar o recarregamento, fazendo com que o compilador do TypeScript reprocesse cada arquivo para cada alteração.

De qualquer forma, não posso ser a única pessoa que usou essas ferramentas além dos projetos de brinquedos, por isso estou perguntando se alguém tem uma solução melhor; já que além dessa questão, tudo está funcionando muito bem.

EDITAR --------------------------------

OK, vou ter que comer minhas próprias palavras. Os builds caíram cerca de um segundo agora que estou agrupando minhas bibliotecas de terceiros em seu próprio pacote. Aqui está o meu gulpfile atualizado (observe a nova tarefa dev.scripts.vendor e a chamada .external na função buildScripts)

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"]);

No entanto, ainda estou recebendo um problema estranho. Com os sourcemaps desativados (que parecem ter um impacto agora, tanto quanto a velocidade), meu retorno de chamada on ("time", () = > {}) está relatando 60-80ms para cada alteração de arquivo, mas ainda é interrompido por cerca de segundo. Um segundo é sobre tudo o que estou disposto a esperar por isso, então, novamente, estou preocupado que à medida que o projeto cresce, essa espera também pode crescer.

Seria interessante ver em que esse segundo adicional de tempo está sendo gasto, quando o evento está relatando algo muito menor. Talvez eu comece a investigar a fonte um pouco, pois parece que ninguém tem a resposta logo de cara.

OUTRO PROBLEMA este é apenas um sidenote, mas debowerify não funciona mais com isso. Ao usar debowerify + bower, ele continuará a renderizar o módulo necessário na saída final, mesmo se esse módulo estiver listado na lista "externa". Portanto, atualmente com essa configuração, só posso usar os módulos npm, a menos que eu esteja bem em adicionar mais tempo de compilação ao meu pacote de aplicativos.

Além disso, aprendi que debowerify irá substituir os módulos npm, e que é baseado na lista de diretórios de bower_components, NÃO no seu arquivo de configuração do bower. Eu tinha o jQuery instalado no npm e apenas o bootstrap no bower; mas como o bootstrap derrubou o jQuery como uma dependência, o módulo jQuery do bower estava sendo carregado preferencialmente sobre o jQuery do NPM. Apenas um aviso para as pessoas.

    
por nlaq 20.11.2015 в 10:03
fonte

1 resposta

2

Esqueça isso, apenas use o último pacote web TS +:)

    
por Dimitar Mazhlekov 16.10.2016 / 23:34
fonte