shellscape / webpack-plugin-serve

A Development Server in a Webpack Plugin
http://shellscape.org
Mozilla Public License 2.0
337 stars 53 forks source link

Performance Questions #137

Closed PeterKottas closed 5 years ago

PeterKottas commented 5 years ago

How Do We Reproduce?

Apologies, it appears all my issues are quite hard to reason about. This one is performance related which is historically among the worst candidates for a quick fix. But I think it's good to have a place to discuss things anyways. After implementing webpack-plugin-serve into our workflow, I've noticed a relatively significant performance drop. I was curious if anybody else noticed something similar.

Expected Behavior

This plugin approach should be faster or worst case equal in performance to the good old webpack-serve.

Actual Behavior

Once again, I need to point out, these are my results and mine only, others might have a different experience.

--- Build Rebuild
webpack-serve 39s 4.24s (avg of 10, 3.2-4.5)
webpack-plugin-serve 46s 6.54s (avg of 10, 3.8-9.5)

Notice that webpack-serve performance was fairly stable, with webpack-plugin-serve the numbers were all around the place.

Major differences I see are:

I also noticed that vscode becomes quite unresponsive during rebuild which is something I haven't seen previously. The version of webpack-serve I am comparing this with is 2.0.3.

shellscape commented 5 years ago

This may be due to a number of things. One of the key differences between 2.x webpack-serve (or anything using webpack-dev-middleware) and webpack-plugin-serve is that our plugin writes to the file system, rather than keeping all files in memory. That might account for the discrepancies you're seeing. There may be other factors at play as well; the type of hard disk you have, other file i/o operations running (Windows is notoriously bad at that), etc. I can't speak to VSCode locking up - we're not doing anything that would adversely affect that specifically (I don't eve use VSCode, but I've never seen Atom choke while a build is in progress with the plugin).

I'd bet my lunch the varied numbers is due to the disk write versus memory write. Writing to disk was a very conscious decision we made due to the myriad of memory issues that webpack has, without writing a build into memory and accessing it there. webpack-dev-server has had an incredible amount of issues related to reading the bundle files from memory, and many have been open for a long time. It was just more headache than it was worth.

PeterKottas commented 5 years ago

Hmm, ok that sounds interesting. Obviously I had no idea as I never looked at the code of this lib in great detail, so thanks for making that clear :)

Generally speaking writing to disk as opposed to memory sounds like a bad idea (that's the scientist in me speaking), but I trust the decision made was valid. Webpack can be weird about things, and yes, I've seen it fall apart a few times complaining about memory issues.

That being said, especially for a bigger project, this performance thing can be an issue. On average 2sec per rebuild is not insignificant. I wonder if there's anything that can be done about this.

shellscape commented 5 years ago

@PlayMa256 and @sibelius are our dog-fooding maintainers and I know they use it for some larger projects, they might be able to speak towards improving build times. This StackOverflow question and discussion about a RAMDrive for compiling might be of interest. And some older, but possibly relevant instructions for creating a RAM Drive in Windows that apparently achieves 10gb/sec https://www.tekrevue.com/tip/create-10-gbs-ram-disk-windows/, which you might be able to use for development builds.

This certainly won't be the solution for everyone. That's a goal that webpack-dev-server undertook, and I believe ultimately why it has/had so many problems.

matheus1lva commented 5 years ago

I don't know what can be considered a fairly large project, but I used WPS on a different range of projects and never had a bottleneck, everything worked as expected and most of the time I was on a virtual machine, using ssd. The significant differences in time are related to ram vs HDD for sure. You can remove some optimizations from webpack during dev to try to reduce it's time. I was playing around with webpack and me and Sibelius, we tweaked an internal thing on webpack to disable dynamic import for dev mode and our builds decreases a lot!

sibelius commented 5 years ago

Most of performance problem is with webpack 4 and doing a lot of code split

it will code split all files even in development, generating a lot of overhead

You can use this patch-package to fix it https://gist.github.com/sibelius/baf12454c371e9d6c728376c39d9f1e0

This patch-package breaks HMR, but it makes the reload faster

check the PR here https://github.com/webpack/webpack/pull/8645

PeterKottas commented 5 years ago

Great info from all of you guys. Thanks! As it stands now, I will probably stay with the older version for the main app. Performance drop there is pretty significant. But I am happy to use this for smaller websites. Great work on the lib!

@PlayMa256 It's a huge dashboard app with hundreds of components and pages. It's not that it's a bottleneck per say, it's mostly the performance drop that makes it slightly worrying. Obviously if you are used to it, it's fine and you can easily live with the situation. But for me right now, it's like giving up 30% of speed for basically no new features.

@sibelius Yeah there's a lot of code splitting in this app. If I can make it work much faster, 30% won't be such a big impact. Not having HMR would be an issue though.

sibelius commented 5 years ago

you can use this plugin https://github.com/MLoughry/eager-imports-webpack-plugin

to have the same effect of this patch-package

matheus1lva commented 5 years ago

@PeterKottas Give this plugin a try. It helps increasing the performance since it does not write every single splitted chunk to disk (webpack acts like there is no code split feature) and hence you have less operations being done

sibelius commented 5 years ago

I think we need to profile to see where is the bottleneck

@PeterKottas can you share both config for wps and webpack-serve?

PeterKottas commented 5 years ago

I've added the plugin, the result is quite surprising. While it stayed slow, pretty much the same avg speed of around 6second, it actually got much more stable. I am getting 6sec on most rebuilds as opposed to 3.8-9.5 before. It sort of makes sense, but unfortunately is stays slow :(

@sibelius The setup for wps

new Serve({
   port: 54762,
   open: true,
   historyFallback: true,
   hmr: true,
   host: "localhost",
   static: "build",
   progress: false
})

and for ws

serve: {
   port: 54762,
   clipboard: false,
   content: "build",
   open: true,
   add: (app, middleware, options) => {
     const historyOptions = {
          // ... see: https://github.com/bripkens/connect-history-api-fallback#options
     };

     app.use(convert(history(historyOptions)));
   }
}
shellscape commented 5 years ago

for basically no new features

:) That's not entirely correct. WPS actually has proper HMR, and supports HMR across multiple compilers.

We've got a good comparison here: https://github.com/shellscape/webpack-plugin-serve/blob/master/.github/FEATURES.md. Though if you're not using any of the feature differences, it'll be equivalent.

If you have permission to share your entire webpack config, we might be able to spot something amiss.

PeterKottas commented 5 years ago

Sorry, I misspoke. Obviously you put a lot of great work into this and it's clear there's plenty of cool features. You're right, I am just not using any of them, which explains my previous statement.

I am the boss so the permission is not such a big deal :) Be warned though, it's wild.

const path = require("path");
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const merge = require("webpack-merge");
let FaviconsWebpackPlugin = require("favicons-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var currentEnv =
  (process.env && process.env.NODE_ENV && process.env.NODE_ENV.trim()) ||
  "local";
var isProd = currentEnv === "production";
var isLocal = currentEnv === "local";
var OfflinePlugin = require("offline-plugin");
var HtmlWebpackHarddiskPlugin = require("html-webpack-harddisk-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
// const CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
var BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
var GitRevisionPlugin = require("git-revision-webpack-plugin");
const history = require("connect-history-api-fallback");
const convert = require("koa-connect");
const PreloadWebpackPlugin = require("preload-webpack-plugin");
const RobotstxtPlugin = require("robotstxt-webpack-plugin");
const WebAppWebpackPlugin = require("webapp-webpack-plugin");
// const { WebpackPluginServe: Serve } = require("webpack-plugin-serve");

var gitRevisionPlugin = new GitRevisionPlugin();
var getAppConfig = envName => {
  var finalConfig = require("./config.json");
  if (envName) {
    try {
      var configTransform = require(`./config.${envName}.json`);
      if (configTransform) {
        finalConfig = Object.assign(finalConfig, configTransform);
      }
    } catch (e) {}
  }
  finalConfig.buildOn = new Date().toUTCString();
  finalConfig.buildVersion = gitRevisionPlugin.version();
  finalConfig.buildBranch = gitRevisionPlugin.branch();
  finalConfig.buildCommitHash = gitRevisionPlugin.commithash();
  finalConfig.buildFor = currentEnv;
  return finalConfig /* = { default: finalConfig }*/;
};

const convPaths = require("convert-tsconfig-paths-to-webpack-aliases").default;

// Needs to be valid JSON. All comments in tsconfig.json must be removed.
const tsconfig = require("./tsconfig.json");
Object.keys(tsconfig.compilerOptions.paths).forEach(
  key => !key.endsWith("*") && delete tsconfig.compilerOptions.paths[key]
);
const aliases = convPaths(tsconfig);

let baseRoute = `https://${
  isProd ? "dashboard" : "stg-dashboard."
}guestbell.com`;

module.exports = env => {
  // Configuration in common to both client-side and server-side bundles
  console.log("Environment :", currentEnv);
  let htmlPluginOptions = {
    alwaysWriteToDisk: true,
    filename: "index.html",
    template: "./ClientApp/index.template.ejs",
    googleAnalytics: {
      trackingId: "",
      pageViewOnLoad: true
    }
  };
  if (isProd) {
    htmlPluginOptions.googleAnalytics = {
      trackingId: "",
      pageViewOnLoad: true
    };
  }
  if (!isLocal && !isProd) {
    htmlPluginOptions.googleAnalytics = {
      trackingId: "",
      pageViewOnLoad: true
    };
  }
  // Configuration for client-side bundle suitable for running in browsers
  var config = {
    config: JSON.stringify(getAppConfig(currentEnv))
  };
  const clientBundleOutputDir = "./build";
  const clientBundleConfig = envName => ({
    mode: isLocal ? "development" : "production",
    resolve: {
      extensions: [".js", ".jsx", ".ts", ".tsx"],
      alias: {
        ...aliases,
        pica: "pica/dist/pica.js",
        "react-dom": "@hot-loader/react-dom"
      }
    },
    entry: {
      //...(isLocal ? { 'react-hot-loader/patch': 'react-hot-loader/patch' } : {}),
      site: "./ClientApp/boot-client.tsx",
      silentRenew: "./ClientApp/silentRenew/index.ts",
      //...(isLocal ? { "webpack-plugin-serve/client": "webpack-plugin-serve/client" } : {})
    },
    serve: {
      port: 54762,
      clipboard: false,
      content: "build",
      open: true,
      add: (app, middleware, options) => {
        const historyOptions = {
          // ... see: https://github.com/bripkens/connect-history-api-fallback#options
        };

        app.use(convert(history(historyOptions)));
      }
    },
    module: {
      rules: [
        {
          test: /\.(j|t)sx?$/,
          include: [path.resolve(__dirname, "ClientApp")],
          use: {
            loader: "ts-loader", //'awesome-typescript-loader?silent=true',
            options: {
              // disable type checker - we will use it in fork plugin
              transpileOnly: isLocal ? true : false,
              experimentalWatchApi: isLocal ? true : false
            }
          }
        },
        {
          test: /\.(scss|css)$/,
          use: [
            isLocal
              ? {
                  loader: "style-loader",
                  options: {
                    sourceMap: true
                  }
                }
              : {
                  loader: MiniCssExtractPlugin.loader
                },
            {
              loader: "css-loader",
              options: {
                sourceMap: true
              }
            },
            {
              loader: "postcss-loader",
              options: {
                sourceMap: true,
                plugins: loader => [
                  require("autoprefixer")({
                    browsers: ["> 1%", "last 2 versions"]
                  })
                ]
              }
            },
            {
              loader: "sass-loader",
              options: {
                sourceMap: true
              }
            }
          ]
        },
        {
          test: /\.(png|jpg|jpeg|gif)$/,
          use: {
            loader: "responsive-loader",
            options: {
              adapter: require("responsive-loader/sharp"),
              placeholder: true,
              placeholderSize: 50,
              name: "dist/images/[name]-[hash]-[width].[ext]",
              disable: isLocal
            }
          }
        },
        {
          test: /\.(woff|woff2|eot|ttf|svg)$/,
          use: "url-loader?limit=8192&name=dist/fonts/[name]-[hash].[ext]"
        },
        {
          test: /\.(wav)$/,
          use: "file-loader?name=dist/files/[name]-[hash].[ext]"
        }
      ]
    },
    output: {
      path: path.join(__dirname, clientBundleOutputDir),
      filename: "dist/js/[name].[hash].js",
      publicPath: "/", // Webpack dev middleware, if enabled, handles requests for this URL prefix
      chunkFilename: "dist/js/chunk.[name].[hash].js",
      pathinfo: false
    },
    plugins: [
      new CleanWebpackPlugin(),
      new MiniCssExtractPlugin({
        filename: "dist/css/[name].[hash].css",
        chunkFilename: "dist/css/[id].[hash].css"
      }),
      new webpack.DefinePlugin({
        "process.env.NODE_ENV": isLocal
          ? JSON.stringify("development")
          : JSON.stringify("production")
      }),
      new CopyWebpackPlugin([
        {
          from: "ClientApp/assets/server",
          to: ""
        }
      ]),
      new HtmlWebpackPlugin(htmlPluginOptions),
      new HtmlWebpackPlugin({
        alwaysWriteToDisk: true,
        inject: true,
        template: "./ClientApp/silentRenew/silent_renew.ejs",
        chunks: ["silentRenew"],
        filename: "./silent_renew.html"
      }),
      new HtmlWebpackHarddiskPlugin(),
      new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /(en|es)$/),
      new PreloadWebpackPlugin({
        rel: "prefetch"
      }),
      new WebAppWebpackPlugin({
        // Your source logo (required)
        logo: "./ClientApp/assets/favicon/favicon.svg",
        // Enable caching and optionally specify the path to store cached data
        // Note: disabling caching may increase build times considerably
        cache: true,
        // Prefix path for generated assets
        prefix: "dist/favicon/",
        // Inject html links/metadata (requires html-webpack-plugin)
        // false: disables injection
        // true: enables injection if that is not disabled in html-webpack-plugin
        // 'force': enables injection even if that is disabled in html-webpack-plugin
        inject: true,
        // Favicons configuration options (see below)
        favicons: {
          appName: isProd ? "GuestBell Dashboard" : "GuestBell Dashboard stg", // Your application's name. `string`
          appShortName: isProd ? "Dashboard" : "Dashboard stg", // Your application's short_name. `string`. Optional. If not set, appName will be used
          appDescription: `GuestBell is a revolutionary online room service system. It's built for the most important people in the world, your guests.`, // Your application's description. `string`
          developerName: "GuestBell", // Your (or your developer's) name. `string`
          developerURL: "https://guestbell.com", // Your (or your developer's) URL. `string`
          dir: "auto", // Primary text direction for name, short_name, and description
          lang: "en-US", // Primary language for name and short_name
          background: "#323232", // Background colour for flattened icons. `string`
          theme_color: "#10bdc7", // Theme color user for example in Android's task switcher. `string`
          appleStatusBarStyle: "black-translucent", // Style for Apple status bar: "black-translucent", "default", "black". `string`
          display: "standalone", // Preferred display mode: "fullscreen", "standalone", "minimal-ui" or "browser". `string`
          orientation: "any", // Default orientation: "any", "natural", "portrait" or "landscape". `string`
          scope: "/", // set of URLs that the browser considers within your app
          start_url: "/", // Start URL when launching the application from a device. `string`
          version: gitRevisionPlugin.version(), // Your application's version string. `string`
          logging: false, // Print logs to console? `boolean`
          pixel_art: false, // Keeps pixels "sharp" when scaling up, for pixel art.  Only supported in offline mode.
          loadManifestWithCredentials: false, // Browsers don't send cookies when fetching a manifest, enable this to fix that. `boolean`
          icons: {
            // Platform Options:
            // - offset - offset in percentage
            // - background:
            //   * false - use default
            //   * true - force use default, e.g. set background for Android icons
            //   * color - set background for the specified icons
            //   * mask - apply mask in order to create circle icon (applied by default for firefox). `boolean`
            //   * overlayGlow - apply glow effect after mask has been applied (applied by default for firefox). `boolean`
            //   * overlayShadow - apply drop shadow after mask has been applied .`boolean`
            //
            android: true, // Create Android homescreen icon. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            appleIcon: true, // Create Apple touch icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            appleStartup: true, // Create Apple startup images. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            coast: true, // Create Opera Coast icon. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            favicons: true, // Create regular favicons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            firefox: true, // Create Firefox OS icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            windows: true, // Create Windows 8 tile icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
            yandex: true // Create Yandex browser icon. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }`
          }
        }
      })
    ]
      .concat(
        isLocal
          ? [
              new ForkTsCheckerWebpackPlugin(),
              /*new Serve({
                port: 54762,
                open: true,
                historyFallback: true,
                hmr: true,
                host: "localhost",
                static: "build",
                progress: 'minimal'
              })*/
              // Might make sense to use this for local at some point
              /*new webpack.optimize.LimitChunkCountPlugin({
          maxChunks: 1
      }),*/
            ]
          : [
              new BundleAnalyzerPlugin({
                analyzerMode: "static",
                openAnalyzer: true
              }),
              new OfflinePlugin({
                safeToUseOptionalCaches: true,
                externals: [
                  "https://fonts.googleapis.com/css?family=Montserrat:200,300,400,700",
                  "https://fonts.googleapis.com/icon?family=Material+Icons"
                ],
                caches: {
                  main: ["dist/site*.js", "dist/site*.css", "**/*.html"],
                  additional: [":rest:"]
                  // I think we don't need optional as it will not load everything here
                  /*optional: [
              ':rest:'
            ]*/
                },
                // appShell: '/',
                autoUpdate: 1000 * 60 * 60 * 5,
                ServiceWorker: {
                  events: true
                  // navigateFallbackURL: '/'
                }
              }),
              new RobotstxtPlugin({
                host: baseRoute
              })
            ]
      )
      .concat([]),
    externals: config,
    // watch: isLocal,
    devtool: isLocal ? "inline-source-map" : false,
    ...(!isLocal
      ? {
          optimization: {
            minimizer: [
              new TerserPlugin({
                parallel: true,
                sourceMap: isLocal,
                cache: true
              }),
              new OptimizeCSSAssetsPlugin({})
            ]
          }
        }
      : {})
  });
  return [clientBundleConfig(currentEnv)];
};
shellscape commented 5 years ago

Nothing stands out as unusual to me. Just a lot of build steps. Terser and Analyzer might be targets to turn off to see if times improve.

Use of webpack-dev-middleware is not an option for us (that's what writes bundles into memory using memory-fs) as it is problematic, and forcing users to write bundles to memory comes with it's own caveats and issues. So I'm looking into a solution that we might be able to bake in as a feature: ramdisk support.

The idea is that when the server spins up, it creates a ramdisk. This would provide native filesystem methods to a mount point in memory - hopefully making for the same kind perf as memory-fs. Mac and Linux is easy to support, Windows is a bit trickier. I'm going to work in a VM to see if I can make this happen for you. I'd love to get this working right in your env, and it would likely be a welcome option for others.

Update

Windows is proving to be more of a pill than anticipated. I've looked at several different methods that wouldn't have required user interaction or manual steps, and they all have issues. Issues as in they don't work at all haha. What I have found are several free, open source ramdisk methods which unfortunately do require some minimal steps:

If you're looking to boost performance of the build, I would wager this will have a leg up on the old version of webpack-serve, as this is a native filesystem based in ram, versus a custom filesystem module that webpack-dev-middleware uses. I think it would be worth a try for your app.

PeterKottas commented 5 years ago

Tbh it's just purely commented. So at first glance, it looks chaotic. Actually the Terser and Analyze are turned off that's what the isLocal switch is doing. But that's not rly important.

Once again, your commitment is exemplary :) That being said, I am confident that this could be a welcome feature for everybody. I mean 30 something percent, that's sweet. Shame about windows ... hate to see this things made difficult by operating systems ... As an idea it looks totally legit for me though.

I think people seeking that extra performance wouldn't mind installing software. Npm made us all lazy but in the old age, it was fairly common to install things. As long as it's optional of course. That being said, automatic support would be awesome, maybe someday.

I'd be happy to try anything that you send my way.

matheus1lva commented 5 years ago

@PeterKottas So i went experimenting with @shellscape some scenarios and our goal was to capture its first build time + subsequent build times. I did some tests on an application that outputs 51 async chunks (sadly i cannot post on github).

On a linux virtual machine, using SSD: Wps

initial build -> 41.49s
on save -> 11s

WDS

initial -> 39.55 secs
on save -> 8.047 secs

Well, we were not satified yet. I installed ImDisk (mentioned above) on windows to create a ram disk using memory space, sort of to simulate how WDM would do, without messing with a fake filesystem.

first build: 36.45 secs
on save: 11s

That's an 8% performance gain on the initial build!

I hope those numbers help in future discussions!

shellscape commented 5 years ago

So I think that's the route we should go for this. Mac and Linux support commands that we can use to spin up a temporary ram disk for the process, so that will be seamless for the user. On Windows, due to the lack of such commands and abilities, users will have to use a tool like ImDisk or have their files written to disk.

PeterKottas commented 5 years ago

Good stuff @PlayMa256. The initially build looks great. But I am curious, do you have a clue why the incremental build stays around 30% slower than using WDS?

@shellscape I think that's the way to go. As long as you can optionally make it faster with a little bit of extra work, I am pretty sure users would love that.

shellscape commented 5 years ago

If we were looking at 82 seconds versus 60 seconds (30%) I would be slightly more concerned. But that's a 3 second difference at an app that size, which wouldn't concern me greatly. (It would probably be prudent to run several more samples, but there's not much we'd be able to do about that rebuild time on a ramdisk anyhow)

A ramdisk is in-memory so that's going to generally be faster than writing to hard disk drive, and should lighten the load on SSDs.

PeterKottas commented 5 years ago

Maybe I understand it wrong, but these 3 seconds have to do with rebuild on save, right? Because in that case, I think it's actually pretty significant. You might do this 500 times a day so things snowball pretty quickly.

I actually don't care about the initial build that much :) Cause that only happens once for the whole coding session.

shellscape commented 5 years ago

Because in that case, I think it's actually pretty significant. You might do this 500 times a day so things snowball pretty quickly.

500 * 3 / 60 = 25 minutes, or 5% of an 8 hour day 500 saves in a day would be a bit egregious, don't let your PMs know about that haha (I'm not here to tell people how to work 😄)

If build times scaled up to be consistently 30% worse as the bundle size grew (as in the example I gave above) that might be a cause for concern. But hashing over 3 seconds is a bit too far down the micro-optimization road, purely IMHO.

We really only have three choices for your issue-case, because we're limited by webpack and by users' arbitrary configurations of webpack:

  1. Duplicate webpack-dev-middleware
  2. Allow users the means to write to memory without duplicating webpack-dev-middleware
  3. Do nothing

(1) isn't going to happen (that comes with far too many problems) (2) is the most reasonable solution (3) is reasonable, but would likely drive larger app users away

That's pretty much where we're at. For Windows users, your path is to install ImDisk and point your development env builds and static option to the RamDisk drive, or - and I do not mean to make this sound at all curt - use a different project.

PeterKottas commented 5 years ago

People are different. I personally expect HMR/live-reload to be quite quick as I feel it can waste a lot of time just staring at the screen. Especially tweaking styles. Remember that you have to add 500 * 8 / 60 = 66 minutes to your 25. That's annoying to say the least. In other words, lot of time can be saved so I wouldn't call it micro-optimization. But understandably most of that time is lost in webpack, not this plugin.

I understand your reasons, it was mostly curiosity as to why the change from the older package. I am happy to keep using webpack-serve with the big app as that appears to be fairly stable for the time being.

Pretty sure this package will find enough users even without big projects. It's definitely neat and easy to set up.

shellscape commented 5 years ago

This hasn't been abandoned, I've just been super busy. Still have a plan for setting up virtual drive options that should dramatically increase speeds.

shellscape commented 5 years ago

So I've put together a plugin that WPS will eventually make use of: https://github.com/shellscape/webpack-plugin-ramdisk. I need to run some profiling and gather some numbers, and document them before I publish it to NPM and before we bring it into WPS, to make sure it's going to satisfy the need here. Will update when I have more.

PeterKottas commented 5 years ago

Good stuff! I've checked it out briefly and this could definitely be interesting for a lot of people. Keep up the good work!

shellscape commented 5 years ago

We've wrapped profiling and we consistently see 25-32% improvement with the plugin. Even have some non-ssd users claiming 70%. Which is just bananas. Going to close this one, as I've started work on a feature branch to use the plugin. Cheers 🍺