Using imports and script links
To use external JavaScript files in your WebSharper project, there are a couple considerations:
- Is your project a library or a web project?
- Is the JavaScript file modular (ES6) or not?
- If a library, do you want to embed the JavaScript file as a resource or just link to it from a CDN or depend on npm?
First we'll see how to embed/link external JavaScript in library projects.
Embedding files with extra.files file
If an extra.files file is present in the project root folder, it supports embedding or copying files to output directory based on project type. This is how it works:
- Create an
extra.filesfile next to your project file. It should be a plain text file.- Comment lines can be added with
//. - The rest of the lines must be like
FilePatternand{FilePattern}, where a file pattern can be a single file name relative to project root. - Patterns can also include
*and**wildcards for any partial name and partial paths.
- Comment lines can be added with
- For
web,spa,bundleonly, andhtmlproject files, aFilePatterncopies over the matched files to the output directory. For other project types it does nothing. - For
web,spa,bundleonly, andhtmlproject files, a{FilePattern}copies over the matched files under the correct assembly-specific output folder likeoutputDir/Scripts/WebSharper/AssemblyName. This ensures that import paths from F#/C# code will work if they are relative paths from the project directory to the file location, as the relative path is preserved. - For other project types, a
{FilePattern}embeds the files in the assembly, with the relative path preserved in the embed key, and it will be unpacked with the same relative path in a web project. This ensures the same guarantee for libraries/WIG projects, that resources at relative paths will continue to work when they are utilized. - The
WebSharper.WebResourceattribute is now obsoleted, but still works. Recommended approach is to remove these assembly-level attributes, as well as removing the files asEmbeddedResourcefrom the projects (for F#, you can keep them asNonefor VS solution tree visibility), and useextra.filesinstead.
Embedding a file with atribute (old method)
If you have a JavaScript file, first you need to add it as an embedded resource in your project file.
Then add the following assembly attribute to your code:
This marks the file to be unpacked by WebSharper into the output folder (usually it will end up in wwwroot\Scripts\WebSharper) when a web project is built.
Using a JavaScript module
If the JavaScript file is a module, you can create bindings for it using the Import attribute. This allows you to use the functions and variables defined in that module in your WebSharper code.
Here, the Import attribute specifies the JavaScript file to import, and the Inline attribute is used to define how the function or variable should be called in JavaScript.
You can use the $import special value to refer to the imported valu defined by the Import attribute.
Alternatively, you can use the WebSharper.JavaScript.JS.Import family of function to import a JavaScript module and use its exports directly in your code.
The JS.ImportDynamic function can be used to import a module dynamically at runtime, which is useful for code-splitting or loading modules conditionally.
The relative paths are automatically changed by WebSharper when necessary for multi-project solutions, which unpacks each project into its own folder.
JS.ImportFile function adds a side-effecting import, that can be used for css and other non-code resources.
Importing npm packages
To use npm, instead of a relative path, you can use a package name.
To mark your project as an npm package consumer, you can add the following to your project file:
Then when the library is consumed by a web project, the npm package can be installed automatically by the femto tool. Run once:
Then run femto in your project folder to install the dependencies into package.json file. For C# projects, you need to provide project name like femto MyProject.csproj
Linking to a script
For non-modular JavaScript files or css, you can create a script/link in your HTML pages automatically by using the Require attribute on a type or method.
It expects a type argument that implements the WebSharper.Core.Resources.IResource interface, which provides full control over what to write into the HTML head section. For example:
In all cases when defining a resource, we then can annotate the code that requires it:
For most cases, you don't need to implement a resource class from scratch but can inherit from the WebSharper.Core.Resources.BaseResource type which provides robust functionality to handle both embedded resources and extarnal URLs.
For an embedded resource, you can use:
The Resources.BaseResource depends on some Reflection for checking that the embedded resource exists, so make sure to define your resource class in the same project into which you embed your script.
Instead of "test.js", you can also use an external URL. Or you can pass it a list of arguments, the first being a base URL, and the rest scripts to be loaded one after another below all using the same base URL.
For external links, there is also a shortcut without defining a class: the Require attribute can take additional arguments too, and WebSharper will use those to use the matching constructor on the given resource type with those arguments.
This allows to use BaseResource itself with a Require:
But even in this case, defining separate resource types is useful when you want to reuse them or define dependencies between resources.
You can put a Require attribute on a Resource type to make it depend on another resource type, and WebSharper will ensure that the dependencies are rendered in the correct order.
In Server-side WebSharper code
Sometimes you might need to depend on a resource without having any client side
code; typically, a CSS file. In this case, you can add the web control
WebSharper.Web.Require anywhere in your page. This control does not directly
output any HTML at the location where you put it, but it incurs a dependency on
the resource that you pass to it.
Here is an example UI page with a dependency on TestResource from above:
Hashes on resource links
WebSharper computes a hash of all generated files, and files embedded and referred to from a WebResource attribute. These hashes are added as query parameters on script links generated by the sitelets runtime to avoid browsers caching an outdated version.
Overriding Resource URLs
External resources implemented using BaseResource can have their URL
overridden on a per-application basis. For example, you can force your
application to use a different version of JQuery than the one used by default
by WebSharper.
This configuration is done in the application configuration file appsettings.json, under the websharper section.
To override a given resource URL, simply add an appSetting whose key is the fully qualified name of the resource, and whose value is the URL you want to use. For example, to tell WebSharper to use a local copy of JQuery located at the root of your application, you can add the following to your application configuration file:
In appsettings.json:
Note that the fully qualified name is in IL format. This means that nested
types and types located inside F# modules are separated by + instead of ..
If you are a library author and have a resource declared by directly
implementing the IResource interface, you can make it configurable by using
the function ctx.GetSetting, which retrieves the setting with a given key
from the application configuration file.
Downloading resources
The BaseResource class also supports a toggle to download external URL scripts at compile-time, to serve from local server.
To do this, first set the "downloadResources" setting in wsconfig.json to true.
Also add this runtime setting to appsettings.json so that WebSharper runtime will insert the links to downloaded files in your pages instead of online resources: