-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Allow apps to include module js / ES6 scripts #36057
Conversation
* @see appendIfExist() | ||
*/ | ||
protected function appendScriptIfExist($root, $file, $webRoot = null) { | ||
if (!$this->appendIfExist($root, $file . '.mjs', $webRoot)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because of the changes above that prevent throwing AppPathNotFoundException it could happen that $root
and $webRoot
are null
to preserve the original behavior you'd likely need to throw that exception here after checking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the original behavior, as previously \OC_App::getAppPath
was used which did not trow but return false
if not found.
So this behavior is kept by assigning false
to $app_path
and $app_url
and just ignore AppPathNotFoundException
above (if it is raised, the value would stay false
).
If $app_path
is false
then appendIfExist
does skip it and if both are false, then this is handled by the line 115 (next code below the
if(strpos` block)
if ($app_path === false && $app_url === false) {
// ...
But I agree that this is not that obvious from the code without digging into it. I tried to make this more clear and self explaining (see latest commit).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice addition!
see comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not really understand what this does given my low js knowledge, but left a few comments regarding PHP code quality.
550da80
to
e5134f3
Compare
e5134f3
to
5747a35
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 👍
@susnux This looks good. Do you have an example of how this would be used? I'd like to give it a try to understand it better. |
@max-nextcloud
import MyComponent from './my-component.js'
// ...
import MyComponent from './my-component.js'
// ...
export default {
// vue stuff
} But a more exciting thing this would allow us: Using vite instead of webpack, as vite uses ESM for module loading.
For me the difference between webpack (ES5) and vite (ES6) is huge:
Moreover this could be used later for other things, like e.g. sharing modules, I can image having a nextcloud wide importmap which provides aliases for common modules, like |
057e3d8
to
6577ea8
Compare
…Locator` Move from `\OC_App::getAppPath` to `IAppManager::getAppPath`. Signed-off-by: Ferdinand Thiessen <[email protected]>
Enable module js (ES6) support on the `JSResourceLocator`. This changes `JSResourceLocator` to look for `.mjs` files first to allow applications to provide a fallback `.js` for older Nextcloud versions. Signed-off-by: Ferdinand Thiessen <[email protected]>
Signed-off-by: Ferdinand Thiessen <[email protected]>
If apps are installed in non standard app paths, we need to check `$app_path/$script` instead of only doing so for translations. Without this it would fallback to `.js` extension even if a `.mjs` file exists. Also tried make the code more selfe explaining. Signed-off-by: Ferdinand Thiessen <[email protected]>
6577ea8
to
a3595f7
Compare
I rebased this, CI is happy. Anything else I can help with to get this further? :) |
@susnux This sounds super exciting on so many levels. I have not had time to play with it yet but plan to do so in the next days. I had a look at the code and see that the comments by @come-nc were addressed and it looks good to me. I'd love to see this in asap - and we're really short before releasing Nextcloud 26. So I am wondering if we should try to get this in or not. Based on your instructions I am mostly thinking about the following scenario:
My gut feeling says Nextcloud would look for We'd obviously need to document the necessary changes to I also don't know if postponing this merge to land after the branch off of @juliushaertl, @skjnldsv, @nickvergessen You're more familiar with release processes and ways to handle such things. What's your take on this? |
Wait 1 more week until stable26 is branches off and then we can merge this as the first 27 feature. |
* Try to find ES6 script file (`.mjs`) with fallback to plain javascript (`.js`) | ||
* @see appendIfExist() | ||
*/ | ||
protected function appendScriptIfExist(string $root, string $file, string $webRoot = null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have performance implications as it will always search first for a .mjs before searching for the .js? Is the result cached?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will take twice the time, but I do not know if checking if a file exists is really that expensive.
Checking mjs first is required for backwards compatibility. This way you can provide .js
files for older Nextcloud releases and .mjs
files for NC27. So your app can support multiple versions.
Of cause one could add a locator cache, but I am not sure how to invalidate the cache.
This is too late for nc26. |
Time for a |
Is this generated from the
Waiting documentation PR: nextcloud/documentation#9909 |
Signed-off-by: Ferdinand Thiessen <[email protected]>
short version: detailed: Additionally, some servers or caching systems may use the MIME type to determine how to handle the content. For example, a server may compress content with gzip if the MIME type is "application/javascript", but not if the MIME type is "text/javascript". Using the wrong MIME type could therefore affect the performance. When a browser fetches an ECMAScript module with the type="module" attribute, it will treat it as a module and perform some additional processing, such as loading the module dependencies. The application/javascript-module MIME type also allows you to use the import and export statements to create and consume modules. So, using the application/javascript-module MIME type for .mjs files can help ensure that the browser processes them as ECMAScript modules and enable the full benefits of this technology. I have created this post from my general knowledge, unaware of any other reasons that may lie in the code of the server that I am not aware of. If that's the case, I apologize |
Hey :)
This is not correct, as per IETF RFC 9239 With which servers did you experienced that issues ( |
As I see now, the /etc/mime.types in debianoid systems has also been updated. That's exactly what I feared, that I might be building on old imperfect information after all. Hence my caveat in the last paragraph |
I don't know where to report this, but since you seem to be the expert, shouldn't this be updated in the documentation as well? |
@ernolf Good point I will file a PR to fix this. |
Summary
Allow apps to provide scripts as ES6 modules by adding a
type="module"
to script tags of module files.This is done by changing
JSResourceLocator
to also look for.mjs
files, and fallback to.js
(this allow app developers to provide both files so their apps can be used even on Nextcloud version not supported this feature while using the modern scripts on new Nextcloud versions).The benefit of this is apps are no longer required to rely on module loading from webpack & co but can utilize the module loading of the browser (fully supported by all of our browser targets). Moreover this allows to create much smaller bundles.
Example:
26580 KiB
7332 KiB
11748 KiB
4068 KiB
But as said it is even possible to now to quit using a bundler at all and let the browser load needed modules,
as something like this is possible:
Other considered solutions
I also considered adding a flag on
OC\Util::addScript
(e.g. anisModule
parameter).But this would require to rewrite / change a lot of internal utilities as this information must be carried along through
the
OC\Util
, theTemplateLayout
(which also would have to work with deprecatedOC_Util
scripts), theJSResourceLocator
and then be printed by the template functions.TODO
.htaccess
)Checklist