typescript - Browserify + Watchify + Tsify + Gulp 的性能问题

标签 typescript gulp browserify watchify tsify

我有一个“中等”的 Typescript 应用程序(例如,不是微不足道的,但也不是企业级的,数千行)依赖于 jQuery、React 和 SocketIO——以及其他较小的库。

我目前的 gulpfile 是这样的:

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

一切都按预期工作,但是,使用 watch 任务时的构建时间需要很多秒。奇怪的是,我的任务报告脚本的重新编译发生在 500 毫秒以下(“时间”事件的事件处理程序),但如果我在脑海中数数它直到三到四秒后才完成.

请注意,在我粘贴现有的 TypeScript 代码之前,我正在加载/捆绑 jQuery、React、Moment 和我使用得非常快的其他库。因此,我认为使用单独的供应商捆绑包不会加快任何速度。此外,不写出源映射似乎也不会影响性能。

在切换到 browserify 之前,我使用 gulp-typescript 进行编译,使用 requirejs 进行模块加载。这些构建花了不到一秒钟的时间。但是,由于其他原因,requirejs 导致了问题 - 无论哪种方式,我都想从 AMD 转移到 CommonJS。

目前这不是一个大问题,但随着项目的增长,它肯定会导致我的开发流程出现问题。对于只有这么大的项目,处理更大的项目需要多长时间?

此外,它还导致 Visual Studio 出现问题。这是一个 ASP.NET 5 应用程序,Visual Studio 显然坚持在每次更改时重新加载/重新解析捆绑的 JavaScript 文件,导致每次更改后 IDE 延迟 1-2 秒:在重新编译本身需要 3-4 秒。该脚本正在呈现到我的 wwwroot 文件夹,并且似乎无法使用 ASP.NET 5 工具“排除”脚本子文件夹。

我知道我在某处遗漏了一些东西。一个可能的问题是 tsify 没有使用 typescript 的“项目”功能来实现重新加载,导致 TypeScript 编译器为每次更改重新处理每个文件。

无论如何,我不可能是唯一一个在玩具项目之外使用过这些工具的人,所以我在这里问是否有人有更好的解决方案;因为除了这个问题,一切都很好。

编辑 - - - - - - - - - - - - - - - -

好吧,我不得不吃我自己的话。由于我将第三方库捆绑到他们自己的捆绑包中,因此构建时间缩短到大约一秒钟。这是我更新的 gulpfile(注意新的 dev.scripts.vendor 任务和 buildScripts 函数中的 .external 调用)
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"]);

但是,我仍然遇到一个奇怪的问题。禁用源映射(现在似乎对速度有影响),我的 on("time", () => {}) 回调报告每个文件更改 60-80 毫秒,但它仍然挂起大约一秒钟.一秒钟是我愿意等待的全部内容,所以我再次担心随着项目的增长,这种等待也会增加。

当事件报告的内容要小得多时,看看这额外的一秒时间花在了什么上会很有趣。也许我会开始深入研究一下源代码,因为似乎没有人能立即得到答案。

另一个问题 这只是一个旁注,但 debowerify 不再适用于此。使用 debowerify+bower 时,它将继续在最终输出中呈现所需的模块,即使该模块列在“外部”列表中。因此,目前使用此设置,我只能使用 npm 模块,除非我可以为我的应用程序包添加更多编译时间。

此外,我了解到 debowerify 将覆盖 npm 模块,并且它基于 bower_components 的目录列表,而不是您的 bower 配置文件。我在 npm 中安装了 jQuery,并且只在 Bower 中安装了 Bootstrap ;但是由于 bootstrap 将 jQuery 作为依赖项拉下来,所以 bower jQuery 模块优先加载而不是 NPM jQuery。只是为人们提个醒。

最佳答案

忘记这个,只使用最新的 TS + webpack :)

关于typescript - Browserify + Watchify + Tsify + Gulp 的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33822663/

相关文章:

node.js - 使用 gulp 时。有什么方法可以抑制某些任务的 'Started' 和 'Finished' 日志条目

javascript - 使用 gulp.js 编译 HTML 部分

使用 Webpack 编译的 Javascript 失败并注入(inject)了奇怪的代码

vite - 有 vite 的 browserify 吗?如何在基于 vite 的项目中使用 webrtc-swarm?

javascript - 在 Gruntfile.js 中使用 grunt-browserify

javascript - 测试未使用 Jest 调用的回调?

angular - 将 Ionic 存储项作为字符串获取

javascript - 如何在 JSFiddle 上使用 CommonJS 模块?

javascript - 获取对象的所有可能组合,其中值的总和与数字匹配

angular - 如何更改 Angular Material select 中的滚动条样式?