針對一些共用工具程式庫,我習慣在專案加入docfx.msbuild,每次編譯就同步產出API文件,讓文件永遠與最新版程式同步,十分方便。

不過開發久了便覺得每次編譯都重新產生文件會拖累效率,不是個好主意。以手邊的一個程式庫專案為例,沒加上DocFx前大約一秒內就能編譯完成,DocFx文件製作較耗時,動輒要耗用5-6秒,編譯時間整整拖長五倍以上,對性急如火人生苦短的中年程序員來說,彷彿感受到寶貴的職業生涯正在平白流逝,眼看累積3000安的希望愈來愈渺茫,很是煎熬。

以下是一個實例,DocFx編譯部分就花了5.821秒:

2>  Verbose: [Build Document.Apply Templates]Resource "partials/namespaceSubtitle.tmpl.partial" is found from "embedded resource docfx.Template.default.zip"
2>  Verbose: [Build Document.Apply Templates]Transformed model "X:\TFS\src\MyWebApi.Client\obj\api\MyWebApi.Models.yml" to "_site\api/MyWebApi.Models.html".
2>  Info: [Build Document.Apply Templates]Manifest file saved to X:\TFS\src\MyWebApi.Client\_site\manifest.json.
2>  Info: [Build Document]Building 85 file(s) completed.
2>  Info: Completed building documents in 3927.7096 milliseconds.
2>  Verbose: Disposing processor ConceptualDocumentProcessor ...
2>  Verbose: Disposing build step BuildConceptualDocument ...
2>  Verbose: Disposing build step CountWord ...
2>  Verbose: Disposing processor ManagedReferenceDocumentProcessor ...
2>  Verbose: Disposing build step ApplyOverwriteDocumentForMref ...
2>  Verbose: Disposing build step BuildManagedReferenceDocument ...
2>  Verbose: Disposing build step FillReferenceInformation ...
2>  Verbose: Disposing processor ResourceDocumentProcessor ...
2>  Verbose: Disposing processor RestApiDocumentProcessor ...
2>  Verbose: Disposing build step ApplyOverwriteDocumentForRestApi ...
2>  Verbose: Disposing build step BuildRestApiDocument ...
2>  Verbose: Disposing processor TocDocumentProcessor ...
2>  Verbose: Disposing build step BuildTocDocument ...
2>  Info: [Apply Theme]Theme is applied.
2>  Info: Completed executing in 5821.8844 milliseconds.
2> 
2> 
2>  Build succeeded.
2>      0 Warning(s)
2>      0 Error(s)
3>------ Build started: Project: ITForms, Configuration: Debug Any CPU ------
3>  ITForms -> X:\TFS\src\FORM\ITForms\bin\ITForms.dll
========== Build: 3 succeeded, 0 failed, 3 up-to-date, 0 skipped ==========

然而,真有必要每次編譯都重製API文件嗎?事實不然,理論上API文件只有在型別、方法介面變動時才需要更新。開發階段有很高比例的編譯動作是為了修Bug、調整寫法,此時更新API文件純屬空耗資源,平白浪費時間。

為拯救中年程序員所剩無幾的青春,我開始研究如何在專案加個開關,必要時再產生文件,平時則略過DocFx程序以縮短編譯時間。憑藉先前研究TFS Build Serivce時對MSBuild與.csproj結構的粗淺了解,我在csproj裡找到以下這段:

<Import Project="..\packages\docfx.msbuild.1.4.2\build\docfx.msbuild.targets" 
  Condition="Exists('..\packages\docfx.msbuild.1.4.2\build\docfx.msbuild.targets')" />

想必這就是DocFx編譯程序,上面已設定Condition條件,docfx.msbuild.targets檔案存在才執行。修改Condition條件,我加上$(DefineConstants.Contains('DOCFX')),指定當定義DOCFX常數時才啟用DocFx編譯。另外,將DocFx文件複製至指定位置的動作則寫成Builds後執行的Target,一定限定遇到DOCFX常數才執行。

<Import Project="..\packages\docfx.msbuild.1.4.2\build\docfx.msbuild.targets" 
 Condition="$(DefineConstants.Contains('DOCFX')) AND 
 Exists('..\packages\docfx.msbuild.1.4.2\build\docfx.msbuild.targets')" />
<Target Name="Copy DocFx Files" Condition="'$(BuildingInsideVisualStudio)' == ''" 
  AfterTargets="Build">
  <Exec 
Command="xcopy /Y /S &quot;$(ProjectDir)_site&quot; &quot;$(TargetDir)..\..\..\WebApi\Docs&quot;"
Condition="$(DefineConstants.Contains('DOCFX'))">
  </Exec>
</Target>
  

至於DOCFX常數要如何設定?如下圖Condiional compilation symbols處,平時不加DOCFX以求快速編譯,當API介面有異動時再加上DOCFX產生文件。

歷經這番調整,算是兼顧效能與功能,編譯專案也恢復往日的速度,不再陷入「花1秒改程式,等10秒看結果」的焦慮,好多了!


Comments

Be the first to post a comment

Post a comment