Visual Studio: How to debug TypeScript in a shared

2019-01-23 20:17发布

Ideally, we could simply add shared TypeScript project reference to another project and be able to use the referenced code just like we can with Visual Basic or C# cross-project references. Alas, that's not available yet.

Hopefully, Microsoft will upgrade Visual Studio in a near-future version so that it supports seamless cross-project TypeScript debugging without having to duplicate shared files. Until then, we need a workaround. Several others have asked a similar question on Stack Overflow:

But none of those questions meet all of the requirements indicated in this question. Here is why the the answers posted in those questions don't meet our needs:

Problems with linking files, either recursively or manually in Visual Studio

  • Debugging and Go To Definition both do not work well, or at all, on linked files. The linked file does not exist when debugging an ASP.NET website.
  • Some helpful plugins view each linked file as a separate file, which slows down code review and debugging across the entire solution (for example, an error in a single linked shared file will show as three separate errors: one for the original file, one for Referencing Project A, and one for Referencing Project B).
  • It's inelegant.

Problems with copying files from the shared project to the referencing project

  • No matter how careful you are, chances are high that you will edit a duplicated file directly, rather than the original shared file; when you rebuild, all your changes in the duplicated file will be lost.
  • Problems with linked files apply here, as well.

Problems with simply referencing shared project TypeScript files

  • The generated map files, which are required for debugging in multiple systems, do not point to the shared projects. Instead, it points to path-relative file references, which breaks shared file debugging.

Other requirements

  • We need to retain the ability to build shared TypeScript directly into each referencing application, rather than using a separate shared website and then including that shared code, because the referencing apps target different ECMAScript versions (e.g. ECMAScript3 for a public website and ECMAScript 5/6 for an admin website for which you can specify the minimum browser version) and different apps reference different shared files (referencing projects reference different groups of files in the shared project via different reference.ts files, thus keeping references neat).
  • Debugging via a shared website is OK in the development environment, but for production builds, the shared code needs to be built directly into the referencing projects.
  • All TypeScript files, including shared files, are compiled into a single file called App.js in each referencing project.
  • Ensure that debugging is possible outside of Visual Studio (so we can debug with Chrome, Firefox, and other browsers that support map files, as well as debug within Visual Studio/Internet Explorer).

Anyone have a solution to this problem, or know if Microsoft is building cross-project referencing (including full debugging support) into Visual Studio 2015?

2条回答
Emotional °昔
2楼-- · 2019-01-23 20:40

The best solution we could come up with to meet all requirements involves the following steps:

  1. Add references to your shared TypeScript files (using the special _references.ts file, or references directly in TypeScript files).

  2. Automatically update the TypeScript-generated map file using PowerShell so it points to either a shared Web Application's Project URL or a Virtual Directory (available for both IIS Express and full IIS).

I realize this looks like a lot of work, but it shouldn't take more than 30 minutes to set up. It works great and will save development effort and time in the long run:

1. Add references to your shared TypeScript files

  • Visual Studio makes this easy: drag a TypeScript file (either individual files or a _references.ts file) from a shared project to a referencing project's _references.ts file or to any other TypeScript files (_references.ts can keep references nice and neat, but it might not benefit all project structures). Note that the _references.ts file must always be in the root of your project in order to work as expected.

Sources

2. Automatically update the TypeScript-generated map file using PowerShell (to enable debugging)

This step ensures that shared references point to the original shared files using a method that works with Visual Studio, Chrome, and Firefox debugging (replace relative shared references with Project URL or Virtual Directory).

To Microsoft: This type of referencing should be configurable and/or automated in a future Visual Studio release, e.g. if a file is referenced from a different project, automatically map the reference to the shared project's Project URL.

Option 1: Your shared code is in a Web Application project.

This works for multiple debugging systems (tested with Visual Studio, Chrome, and Firefox):

  1. Get the shared application Project URL from Properties | Web | Project URL.

  2. Use a Post-build Event to run a PowerShell script that will replace all shared references in your App.js.map files to point to the Project URL.

Example Post-build Command:

Powershell [io.file]::WriteAllText('$(ProjectDir)Scripts\App.js.map', ((gc '$(ProjectDir)Scripts\App.js.map') -replace '../../Shared_TypeScript/','http://localhost:12345/'))

See PowerShell Replace under Sources below for more details.

  1. Make sure you set up your shared Web App project for debugging along with your referencing Web App projects.

Option 2: Your shared code is not in a Web Application project.

This does not work for Visual Studio debugging, but might be a better option for some scenarios, and it's the only known option for non-web application projects (tested with Chrome, probably works for Firefox):

  1. Add Virtual Directories to your IIS Express website configurations that point to your shared TypeScript project: https://stackoverflow.com/a/8929315/2033465 (see the EDIT).

  2. Use a Post-build Event to run a Powershell script that will replace all shared references in your App.js.map files to point to the Virtual Directories you set up above.

Example Post-build Command:

Powershell [io.file]::WriteAllText('$(ProjectDir)Scripts\App.js.map', ((gc '$(ProjectDir)Scripts\App.js.map') -replace '../../GlobalRef/','/GlobalRef/'))

See PowerShell Replace under Sources below for more details.

Sources

If you need to be able to debug TypeScript files in the production environment (not one of our requirements), then you could alter the post-build script to run a different command (similar, but point to your shared website's Virtual Directory instead of localhost). That's outside the scope of this post.

Conclusion

That is by far the best method I could come up with (thanks to all of those other sources) that meets all of the requirements.

Please let us know if you have a better method.

查看更多
老娘就宠你
3楼-- · 2019-01-23 20:46

I was solving similar issue. My requirements was:

  • Have multiple project in one solution organized in the same way as C# projects are, so the solution folder with .sln and sub-folders for each project with .csproj and typescript files.

  • Debugging possibility in VS and IE11 (run through F5 with breakpoins and all that cool stuff)

  • Ideally without additional scripts.

I tried:

  • postbuild powershell script to copy sources to the www root src
  • organize projects in way where startup project was wwwroot and other projects were placed under the src folder of the wwwroot (so inside of the startup project folder under the /src folder)

both solutions were working with appropriate tsconfig (mapping was set as it was necessary), it was working but I was not satisfied.

In first case, the problem is with updating of files. It was working just after rebuild so it was not comfortable so much as it requires restart of IE, build everything, copy everything and it takes so much time. But it works, less or more.

Second solution is better but I was blamed the project structure is messy and strange (what I knew from the scratch and I din't like it too).

So I went bit deeper to the problem and I came with solution of virtual directories. Now, the project structure matches the standard C# project structure, it is possible to debug in IE11 and externally with Chrome (on the IIS Express and the same localhost:port) and it is also possible to use "compile on save" properly including i.e. css modification and page reload instead of rebuild and IE restart.

It is possible to achieve this manually (without additional scripts) or automatically by post-build script on both IIS express (.vs/config/application.host) and IIS (i didn't need the full IIS till now but I am pretty sure it is possible to automate it through command line). If you will not manipulate projects too often I would say that manual update of IIS / applicationhost.config file is enough and works pretty well (of course when the tsconfig is set correctly to generate map files and set sourceRoot for your TS files).

   Search for the 
   .vs/config/applicationhost.config -> <system.applicationHost> -> <sites> -> <site name="YOUR-STARTUP-PROJECT">
   for each project in the solution add\
   <virtualDirectory path="/src/YourSoultionProject1Name" physicalPath="C:\...PATH-TO-YOUR-PROJECT-ROOT-FOLDER-ON-DISK">

For each project also don't forget to set the sourceRoot option of your tsconfig file to /src/YOUR_PROJECT_NAME (or configure the ts compiler in the project properties)

Its the best solution I have found till now. Only the one problem is the .vs is related to user and is not usually transferred to repo so each user has to set it up on its own. Thats the reason (out of others) why I came with the solution bellow


I decided to create additional - build - project which I wanted to avoid in the beginning but it will allow me to do:

  • automatically setup the virtual directories based on projects in the solution after project open or build
  • build wwwroot based on the solution configuration (Debug/Release) and projects content. This includes:
    • process LESS/SASS
    • minify JS/CSS/HTML
    • generate cache.manifest for offline app support
  • debug from Visual Studio in IE or externally in Chrome
  • publish to Azure as usually with web projects
  • clean wwwroot and i.e. js folder
  • monitoring of changes in any file in any project in the solution and applying changes to target file without need of rebuild (based on gulp watch)

I am almost done with it, I'll put link here when I'll finish just to give you idea how I proceeded.

How it works (it will be in the readme, but just to explain in short now):

Currently, I have 6 projects in the solution where 5 of them are "true" TypeScript code with appropriate tsonfig and/or HTML/LESS/SASS/CSS/JSON/IMG resources.

All projects are based on the "HTML Application with TypeScript" template. I have removed everything from them after creation (including the web.config) so it contain only my files now. I also set references to projects in order to be possible to follow required build order. All typescript projects transpiles TS to bin folder (my tsconfig direct compiler to create just one single js file, but it would work for multiple too) of the owning project (including map files and d.ts if required). Other projects then refers to the d.ts in the bin folder of other project using the relative path (../libproject/bin/lib./d.ts) in the tsconfig.

I tried copying to dependent project as C# is doing. It works but it would require a little bit more work and time to get it work properly (and including clean. Postbuild event is not ideal).

6th project is "build" and startup project so it does not contain any "real" code (except the build tools I need). Its based on gulp and a few scripts I have wrote for reading the solution/projects info and configuration.

It also reads my custom config from each project which is controlling the wwwroot build process. Finally, it is copying/processing (minifying) resources fromm solution project to this build/startup project.

I hope I'll finish the first version tomorrow and publish it to GitHub so you can take a look on it and eventually use at least parts of the code. You'll need node.js to have installed.

查看更多
登录 后发表回答