asp.net core mvc 中間件之WebpackDevMiddleware

asp.net core mvc 中間件之WebpackDevMiddleware

  • WebpackDevMiddleware中間件主要用於開發SPA應用,啓用Webpack,加強網頁開發體驗。好吧,你想用來幹嗎就幹嗎,此次主要是經過學習該中間件,學習如何在core中啓用Webpack支持
  • 經過上上篇asp.net core mvc 管道之中間件,大體能夠了解中間件是什麼東西,如今就以中間件爲單位,一個一個點學習各類中間件,瞭解並掌握,最後學會本身寫中間件
  • 該中間件源碼

說明

WebpackDevMiddleware

  • Enables Webpack dev middleware support. This hosts an instance of the Webpack compiler in memory
    in your application so that you can always serve up-to-date Webpack-built resources without having
    to run the compiler manually. Since the Webpack compiler instance is retained in memory, incremental
    compilation is vastly faster that re-running the compiler from scratch.
    Incoming requests that match Webpack-built files will be handled by returning the Webpack compiler
    output directly, regardless of files on disk. If compilation is in progress when the request arrives,
    the response will pause until updated compiler output is ready.html

  • 大概意思是Webpack編譯器實例存在於內存,始終提供最新編譯的資源,增量編譯比從新編譯速度要快得多。任何請求Webpack編譯後的文件,都原樣返回,若是請求到達時編譯沒完成,響應將暫停,直到編譯完成,輸出準備就緒

NodeServices

  • Unlike other consumers of NodeServices, WebpackDevMiddleware dosen't share Node instances, nor does it
    use your DI configuration. It's important for WebpackDevMiddleware to have its own private Node instance
    because it must not restart when files change (if it did, you'd lose all the benefits of Webpack
    middleware). And since this is a dev-time-only feature, it doesn't matter if the default transport isn't
    as fast as some theoretical future alternative.node

  • WebpackDevMiddleware不共享Node實例,也不共享使用的DI配置。由於文件改變時Node服務不能重啓。這是個開發時使用的功能,因此傳輸速度可能不會很快

分析

  • 建立Node實例
var nodeServicesOptions = new NodeServicesOptions(appBuilder.ApplicationServices);
var nodeServices = NodeServicesFactory.CreateNodeServices(nodeServicesOptions);
  • 建立devServerOptions,包含設置webpack.config.js的路徑以及整合在Stratup.cs的設置、模塊熱加載斷點等。這些設置須要傳到Nodeaspnet-webpack模塊,若是是自定義的模塊,那麼參數也是本身定義啦
var devServerOptions = new
{
    webpackConfigPath = Path.Combine(nodeServicesOptions.ProjectPath, options.ConfigFile ?? DefaultConfigFile),
    suppliedOptions = options,
    understandsMultiplePublicPaths = true,
    hotModuleReplacementEndpointUrl = hmrEndpoint
};
  • 下面是經過nodeServices,執行指定aspnet-webpack模塊裏面的方法並獲得結果。參數分別是模塊文件路徑、要調用的方法、傳遞的參數。傳遞給js模塊的參數先序列成json字符串,模塊接收參數後再反序列化成對象
var devServerInfo =
    nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
        JsonConvert.SerializeObject(devServerOptions, jsonSerializerSettings)).Result;
  • 返回結果是Webpack編譯以後的輸出目錄,循環輸出目錄,添加請求代理,代理到全部輸出目錄。超時時間100s, /__webpack_hmr無限超時
  • 代理源碼
foreach (var publicPath in devServerInfo.PublicPaths)
{
    appBuilder.UseProxyToLocalWebpackDevMiddleware(publicPath + hmrEndpoint, devServerInfo.Port, Timeout.InfiniteTimeSpan);
    appBuilder.UseProxyToLocalWebpackDevMiddleware(publicPath, devServerInfo.Port, TimeSpan.FromSeconds(100));
}

// Note that this is hardcoded to make requests to "localhost" regardless of the hostname of the
// server as far as the client is concerned. This is because ConditionalProxyMiddlewareOptions is
// the one making the internal HTTP requests, and it's going to be to some port on this machine
// because aspnet-webpack hosts the dev server there. We can't use the hostname that the client
// sees, because that could be anything (e.g., some upstream load balancer) and we might not be
// able to make outbound requests to it from here.
// Also note that the webpack HMR service always uses HTTP, even if your app server uses HTTPS,
// because the HMR service has no need for HTTPS (the client doesn't see it directly - all traffic
// to it is proxied), and the HMR service couldn't use HTTPS anyway (in general it wouldn't have
// the necessary certificate).
var proxyOptions = new ConditionalProxyMiddlewareOptions(
    "http", "localhost", proxyToPort.ToString(), requestTimeout);
appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions);

結果

  • 建立本身的中間件,自定義配置,運行Webpack服務,只須要建立Node實例,調用本身寫的模塊便可。模塊根據傳過來的配置運行服務便可
  • 關鍵方法
var nodeServicesOptions = new NodeServicesOptions(appBuilder.ApplicationServices); // node配置

var nodeServices = NodeServicesFactory.CreateNodeServices(nodeServicesOptions); // 建立node實例 

// dev服務配置
var devServerOptions = new
{
    webpackConfigPath = Path.Combine(nodeServicesOptions.ProjectPath, options.ConfigFile ?? DefaultConfigFile),
    suppliedOptions = options,
    understandsMultiplePublicPaths = true,
    hotModuleReplacementEndpointUrl = hmrEndpoint
};

// 調用js模塊,運行dev服務,返回輸出目錄
var devServerInfo =
    nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
        JsonConvert.SerializeObject(devServerOptions, jsonSerializerSettings)).Result;

// 添加輸出目錄到代理
foreach (var publicPath in devServerInfo.PublicPaths)
{
    appBuilder.UseProxyToLocalWebpackDevMiddleware(publicPath + hmrEndpoint, devServerInfo.Port, Timeout.InfiniteTimeSpan);
    appBuilder.UseProxyToLocalWebpackDevMiddleware(publicPath, devServerInfo.Port, TimeSpan.FromSeconds(100));
}

private static void UseProxyToLocalWebpackDevMiddleware(this IApplicationBuilder appBuilder, string publicPath, int proxyToPort, TimeSpan requestTimeout)
{
    var proxyOptions = new ConditionalProxyMiddlewareOptions(
        "http", "localhost", proxyToPort.ToString(), requestTimeout);
    appBuilder.UseMiddleware<ConditionalProxyMiddleware>(publicPath, proxyOptions);
}

示例

  • 待更新...
相關文章
相關標籤/搜索