Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better auto-discovery of routes and resources #1463

Open
tomasherceg opened this issue Sep 4, 2022 · 0 comments
Open

Better auto-discovery of routes and resources #1463

tomasherceg opened this issue Sep 4, 2022 · 0 comments
Labels

Comments

@tomasherceg
Copy link
Member

This proposal tries to address several points coming from the real-world applications:

  • In every larger DotVVM application, the DotvvmStartup.cs file gets very long as each route, control, and resource are registered one by one. We have some auto-discovery mechanisms, but they are not so powerful.
  • The division of files into Views and ViewModels folders is reported to be impractical by some users. They suggest keeping everything that is related to the page together in one directory.

Goals

  • The goal is to create a new DotVVM project template with a pre-configured bundler (e. g. esbuild) and implement auto-discovery for controls, resources, and DotVVM pages. The DotvvmStartup.cs file would remain almost empty.

  • As a side goal, we could merge Startup.cs and Program.cs using the minimal approach introduced in .NET 6:

var builder = WebApplication.CreateBuilder(args);
builder.AddDotVVM<DotvvmStartup>();

var app = builder.Build();
app.UseDotVVM<DotvvmStartup>();

app.Run();

Point 1: Keep related things together

DotVVM pages often use custom scripts (JS modules), styles, and other artifacts, which are specific to the page. Also, the ViewModel may be split into multiple classes.

Sometimes the page itself is split into multiple markup controls which are not intended to be used anywhere else - they are page-specific. These should also be kept together with the page.

I see two conventions for how to address this issue:

Options 1: Directory per page

MyDotvvmApp
|--- wwwroot
|--- Pages
|    |--- Admin
|    |    |--- CustomerList
|    |    |    |--- _menu.scss
|    |    |    |--- _utils.ts
|    |    |    |--- CustomerList.dothtml
|    |    |    |--- CustomerList.scss
|    |    |    |--- CustomerList.ts
|    |    |    |--- CustomerListViewModel.cs
|    |    |    |--- Menu.dotcontrol
|    |    |    |--- MenuViewModel.cs
|--- DotvvmStartup.cs
|--- Program.cs
...

The CustomerList folder contains all files that are specific to the page:

  • CustomerList.dothtml and CustomerListViewModel.cs represent the page markup and the viewmodel.
  • CustomerList.scss contains the styles specific to the page.
    • This file could be picked by esbuild and compiled into CustomerList.css.
    • On app startup, it would be auto-discovered by DotVVM and registered as a StylesheetResource (based on the file extension).
    • Also, the RequiredResource control could be automatically appended to the page via server-side style so the user would have the script included automatically.
    • If the user doesn't use SCSS and puts the CSS file in the folder, no problem - it would be also discovered automatically.
  • There is also _menu.scss file. It starts with an underscore to indicate that it's not an "entry-point" SCSS file - it is imported from some other SCSS file. The bundler would ignore these files and it would not try to compile them into CSS.
  • CustomerList.ts is a TypeScript file that can also be automatically compiled into JS and registered automatically as a resource.
    • We will have to distinguish between ScriptResource and ScriptModuleResource. It can be done by the extension (.js vs .jsm), or by some other convention (maybe set globally). Also, the bundler should also transpile the .tsx files if the user uses React components.
  • _utils.ts is the same case as _menu.scss - it is not an entry point to the bundler. It is just a file imported by another file (and the bundler will merge these two files into one resulting JS file).
  • Menu.dotcontrol is a markup control that is specific to the page - it doesn't make sense to use it anywhere else, so it is in the same folder as the page, however, it could also be registered automatically. It comes with its own viewmodel MenuViewModel.cs.
    • DotVVM cannot register the control just to a specific page - it registers them globally, however that should not be such a big deal - having the control here is just an indication that the control is page-specific.
    • We should be careful about the naming conflicts - it is not practical to name the control <cc:Pages_Admin_CustomerList_Menu> - I would register it as <cc:Menu> and report an error when two controls with the same name are registered.

Option 2: File nesting

Another way suggested by some users is to use file nesting - all files would have the same prefix or will be marked with DependentUpon flag in csproj, and the IDE would display them as a hierarchy.

image

MyDotvvmApp
|--- wwwroot
|--- Pages
|    |--- Admin
|    |    |--- CustomerList.dothtml      # the nesting here will be done only by IDE - in the filesystem, all files will be in the same directory
|    |    |    |--- CustomerList.dothtml.scss
|    |    |    |--- CustomerList.dothtml.ts
|    |    |    |--- CustomerList.dothtml.cs
|    |    |    |--- Menu.dotcontrol
|    |    |    |--- Menu.dotcontrol.cs
|    |    |    |--- _menu.scss
|    |    |    |--- _utils.ts
|--- DotvvmStartup.cs
|--- Program.cs
...

This approach would just use a different naming convention which can reduce the nesting, but it is dependent on the IDE capability to understand the nesting. The files not following the convention (_menu.scss and so on) can be marked as DependentUpon in the csproj file, but it is not very convenient for the users.

Personally, I prefer the first approach, but this was also reported by some users.

Point 2: Section-wide resources

Some resources can be related to the entire app, a particular master page, or only to some sub-section of the app. My idea was to include resources from the parent directories automatically.

MyDotvvmApp
|--- wwwroot
|--- Pages
|    |--- Admin
|    |    |--- CustomerList
|    |    |    |--- _menu.scss
|    |    |    |--- _utils.ts
|    |    |    |--- CustomerList.dothtml
|    |    |    |--- CustomerList.scss
|    |    |    |--- CustomerList.ts
|    |    |    |--- CustomerListViewModel.cs
|    |    |    |--- Menu.dotcontrol
|    |    |    |--- MenuViewModel.cs
|    |    |--- Admin.scss
|    |    |--- Admin.ts
|    |    |--- AdminMasterPage.dotmaster
|--- DotvvmStartup.cs
|--- Program.cs
...

The scripts and styles found in the parent directory would be included automatically, and we could also set dependencies between the resources.

In the case above, we would register the CSS files like this:

config.Resources.RegisterStylesheetFile("Admin_Admin-css", "Pages/Admin/Admin.css");
config.Resources.RegisterStylesheetFile("Admin_CustomerList_CustomerList-css", "Pages/Admin/CustomerList/CustomerList.css", dependencies: new[] { "Admin_Admin" });

The AdminMasterPage.dotmaster page could use server-side style to inject the Pages_Admin_Admin stylesheet resource.

Point 3: Global resources

Many resources and controls are treated as global - I suggest introducing the folders Scripts, Styles, and Controls which could contain these files. There may be any folder hierarchies in these directories.

Again, the bundler would browse these directories and compile everything which doesn't start with an underscore.
All .dotcontrol files would be registered automatically.

Summary of the automatic rules

  • The bundler will compile all .scss files not starting with an underscore into .cssfiles.
  • The bundler will compile all .ts or .tsx files not starting with an underscore into .js files.
  • DotVVM will browse the Pages, Scripts, and Styles directories, and registers the script and stylesheet resources automatically.
    • The resource name for styles will be Folder_Folder_File-css - the Pages, Scripts, and Styles folder name will not be included.
    • The resource name for scripts will be Folder_Folder_File
    • We have to be careful about the folders starting with underscore - this would lead to double underscores in the resource name which is not permitted.
  • If there is any .css file in the same directory as the .dothtml, .dotmaster or .dotcontrol page, it will be included in the page automatically.
  • The script files cannot be included because we don't know if the users want to add them via RequiredResource or via @js directive.
  • The controls would be looked for in Controls and Pages directories and would be registered just by the file name under the cc tag prefix. This should be configurable somehow.
  • The pages can be registered automatically based on the @route directive if we decide to implement it. This would need to make some fast mode of tokenizer and parser so they would only read the directives section.

Any comments or suggestions are welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant