Configure projects and workspaces

Completed

Visual Studio Code offers the multi-root workspace feature, which enables grouping different project folders into one workspace. The AL Language extension also supports the multi-root functionality and allows you to work with multiple AL folders including roots and projects within one workspace.

Go through the following steps to work simultaneously on several related projects.

  1. On the File tab of Visual Studio Code, choose Add Folder to Workspace....

  2. Save the workspace file if you plan to open it again.

    This creates a code-workspace file that contains an array of folders with either absolute or relative paths. If you want to share your workspace files, choose the relative paths.

  3. Modify the settings of your files in the Settings editor. You can change your user settings, global workspace settings, or individual folder settings.

It isn't mandatory to use only AL-based roots. Different kinds of projects can be mixed, and each AL project will have its configuration values for the following settings:

  • al.packageCachePath

  • al.enableCodeAnalysis

The al.packageCachePath setting allows you to specify the path to a folder that will act as the cache for the symbol files used by your project. It can be specified in the User Settings, Workspace Settings, or Project Settings.

The al.enableCodeAnalysis setting allows you to enable the execution of code analyzers on your project. It can likewise be specified in the User Settings, Workspace Settings, or Project Settings.

A project reference in an AL-based workspace is defined as a dependency in the app.json file and exists as a project in the workspace. There's no special visual representation of a project reference.

A project reference is the full id, name, publisher, and version of an existing project in the workspace. This is contrary to an application reference where it's enough to specify a minimal version. If you're using workspaces with multiple projects and change the name or publisher of an extension in the workspace, the dependencies in the app.json file must be updated with the new name,** and publisher or you may encounter issues with reference resolution.

In the example below, the project called Leaf defines two dependencies to the projects Middle and Root. Since, both Root and Middle are projects in the workspace, they're considered project references.

Screenshot of the project reference.

The advantage of working with project references is that there's no need to download the symbols for a project reference. They're there as the symbols for the reference project and will be resolved as they're modified. For example, if you add a new method to a codeunit in the Root project and reference the codeunit in the Leaf project, the method will automatically resolve as you touch the Leaf project.

When a project is built with Ctrl+Shift+B, the following will happen:

  1. The .app file is copied to the .alpackages folder of all projects that depend on it.

  2. All project references that might be "dirty" are also built.

If reference resolution stops working, then building the project reference and reinitializing the workspace using Reload Window resolves references.

As a project loads in a workspace, it attempts to load all its project references as a transitive operation. While a project loads, features like IntelliSense and hover over aren't available. Depending on the number of project references and files in the project, this operation can be time consuming.

When the project loads in the workspace, the user is notified with the standard Visual Studio Code progress notification dialogs of the current state. The notifications can be closed, but they won't stop loading a project. If the user selects somewhere else or changes the active project, loading of the previous project will be canceled and the newly selected active project will start loading instead. A project can be loaded by making it active, by opening an .al file, or opening the app.json project file. Once a project is loaded it stays loaded until the AL language server is active, or the Reload Window command, using Ctrl+R is triggered.

Projects that haven't been loaded in the workspace are decorated with the letter N.

Screenshot of the workspace project load.

With the introduction of project references, the publishing logic in a workspace has changed. Publishing, either with Ctrl+F5 or RAD publishing using Alt+Ctrl+F5, will do a set publishing of all the projects that have changed with defining a startup project. The startup project is always the active project.

A project is considered changed if any of its application objects have changed in the sense that the application object is already in the rad.json or will be in the rad.json once the project has been built. This means that if you change an application object, you save it, and then close Visual Studio Code without building the project, the rad.json won't update and then the project won't be considered "dirty".

For example, in a workspace with three projects; LeafMiddle, and BaseLeaf depends on Middle and Base, and Middle depends on Base as illustrated below:

Diagram of a flow.

Assuming that:

  • All the three projects; LeafBase, and Middle have changed.

  • The Leaf project is the current project that is published.

Then all the three projects; BaseMiddle, and Leaf will be part of the set that will be published.

In a scenario where Middle hasn't changed, but Leaf is still the startup project, then only Base and Leaf will be published.

A new file is created to package the set dependencies called *.dep.app. This file gets transferred to the server and it's deleted if publishing of the dependency set is successful.

Although server publishing is an internal step, it does have an impact on the dependency publishing and is useful to know.

For example, in a workspace with two projects; Leaf depends on Base, and External and Indirect are projects outside of the workspace as illustrated below:

Diagram of two project flow.

Assuming that:

  • A workspace exists with Leaf and Base as workspace projects.

  • Base is published.

  • On the server BaseLeafExternal, and Indirect are already installed apps.

The following happens on the server:

  • All apps that depend on Base will be uninstalled, including External and Indirect dependency.

  • Any other apps that directly depend on Base and aren't published in the global scope - in this case Leaf and External - are unpublished.

  • Base is uninstalled, unpublished, and then published.

  • Leaf and External will be published, installed and then compiled against the newly published Base. Important to notice here's that the External app also will be published.

To control how dependency publishing is performed on the server, the launch.json file has a setting dependencyPublishingOption with the following options:

  • Default

    • Set dependency publishing is applied.
  • Ignore

    • Dependency publishing is ignored. This setting should be used cautiously, see note below.
  • Strict

    • Dependency publishing fails if there are any installed apps that depend on the startup project.

With the Ignore setting only Leaf will be published against what has already been published on the server for Middle and Base. If a change has been done on Base that would break Leaf, even though local compilation would pass, the server compilation fails in this scenario. The benefit of using this option is to gain publishing time when Base is a large project. Assuming that Base is published, then Leaf and Middle will be left untouched on the server. Only runtime errors reveal if Base has broken Middle and Leaf.

To remove unnecessary manual work, use the AL: Publish full dependency tree for active project command, which will traverse a project dependency graph in the workspace and install any required projects if these aren't already deployed to the NST server. Find the command by using Ctrl+Shift+P or by using the keyboard shortcut Shift+Alt+W. This calculates the correct order in which to compile and publish the dependencies of the current project and publish them using the launch.json option selected from the current active project.

Only project and app references covered by the workspace will be traversed. If the deployed AL project has dependencies to apps that aren't included in the workspace, these will still have to be present or manually deployed in advance.

If the al.incrementalBuild setting is set to true on workspaces with project to project references, all resolutions happen from the referenced project, instead of happening from an app in the \packagecache folder, which will enhance the build time.