-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
ESM and CSS loading #886
Comments
CSS files are handled by webpack, the typical bundler when choosing ESM. This has nothing to do neither with ECMA nor with the browsers. For more information about webpack and loading CSS: https://webpack.js.org/guides/asset-management/#loading-css |
To me it is a mistake to introduce non-standard features to esm modules. How about if I want to use the unbundled version directly in the browser together with http2? As it is now, it is impossible without preprocessing. |
Sorry for the disappointment for not fitting in your expectation. I think the ESM Version is thought to be bundled with webpack in this project, I'm quite sure that bundled/optimizied/tree-shaked code is still faster than HTTP2 with multiplexing etc... But hey, there is still an AMD Version that you can use. |
@czb I agree. I explicitly tried to avoid any webpack assumptions in the But I could not figure out what to do with the CSS imports. Our CSS is grouped neatly with the corresponding feature. i.e. we don't have a large CSS file which is a "take it all or leave it all", but rather we have written the CSS next to the JS, so each JS file can indicate that it wants certain CSS. You are correct, the source code cannot be loaded in its current shape via a |
Personally, I load css dynamically:
I guess it is equivalent to dynamic import. |
@czb Yes, that is what I also do in the AMD loader I wrote 5 years ago :). But I don't want to do that in each and every JS file where I use some CSS. I also want the ability to be able to collect all used CSS into a single style-sheet at packaging time, so that's why I left |
I could not find any signs of css imports discussions which probably means they will not arrive in a near future. To me, any solution is better than extending javascript by non standard features that are not even at stage 1. |
@czb I am not familiar with the maze of github repositories used by whatwg or w3c nor their politics. I don't expect that Do you happen to know where we can ask someone about the state of affairs for importing CSS ? |
I happen to be part of the group proposing HTML Modules - the ability to import HTML files into JavaScript modules or via I can tell you that the semantics would likely be oriented around a CSS module exporting a Constructible Stylesheet: https://wicg.github.io/construct-stylesheets/index.html ie: import stylesheet from './styles.css';
stylesheet instanceof CSSStyleSheet; // true
// attach to global
document.moreStyleSheets.push(stylesheet);
// or to a ShadowRoot
class MyElement extends HTMLElement {
constructor() {
this.attachShadow({mode: 'open'}).moreStyleSheets.push(stylesheet);
}
} If you wanted to be future-facing to such a spec, the most proper thing to do would be to create a JS modules that has no side-effects and returns a style sheet object from a JS module, ie: styles.css.js: // create a container and scope to hold a style sheet:
const container = document.createElement('div');
const shadowRoot = container.attachShadow({mode: 'open'});
// create a <style> element to add css text to
let styleElement = document.createElement('style');
// add the styles
styleElement.textContent = `
.monaco-editor .accessibilityHelpWidget {
padding: 10px;
vertical-align: middle;
overflow: scroll;
}
`;
// add the <style> to the document so it creates a style sheet
shadowRoot.appendChild(styleElement);
export default let stylesheet = styleElement.sheet; However, because this has no side-effects, this would require rewriting the importing code. Which is kind of ugly without the So for now, because I don't think you're using Shadow DOM yet, I think the best option is to build .css files into JS modules, that attach the CSS to the main document: export default styleElement = document.createElement('style');
styleElement.textContent = `
.monaco-editor .accessibilityHelpWidget {
padding: 10px;
vertical-align: middle;
overflow: scroll;
}
document.head.appendChild(styleElement);
`; Then your import sites can remain the same as the are now. |
Thank you for the explanation @justinfagnani I'm going to think about this for a while, I was hoping to end up in a situation with the I don't believe webpack nor rollup would understand the creation of I also don't think browsers will really like this creation of hundreds of |
Hundreds of stylesheets will be fine. We have lots of experience with styles directly embedded into HTML imports and JS modules on the Polymer team. The future is styles and templates packaged with components, and browsers are well positioned for that. Because modules are statically imported, they can be prefetched as discovered and with http/2 you can get lots of loading in parallel. The tools can analyze the dependency graph and add If the distribution stays dependent on WebPack, can you at least rename the folder and documentation from "esm" to WebPack? It's very misleading that you can't actually load the modules in the browser, IMO. |
So I modified the gulpfile to build .css into .css.js and this gets things closer to working, but there was an exception about
|
Any updates on this? Is it just that we're waiting on ECMA for new CSS loading spec? If so, it would be great to have a ESM spec compliant version using one of the solutions @justinfagnani put forward for the time being! |
I'd love to be able to run the following in the browser (just prototyping myself) - and have it load the editor: <!doctype html>
<html>
<meta charset="utf-8">
<body>
<div id="container">
</body>
<script type="module">
import monaco from '//dev.jspm.io/monaco-editor/esm/vs/editor/editor.main.js';
console.log(monaco);
</script>
</html> Currently it does not load and I see a large number of these errors in the console
Here's an example plnkr I was hoping to be able to hack on using the monaco editor in the browser https://plnkr.co/edit/0fMrMAjNeH2PVGAh206m?p=preview to prototype something... |
@alexandrudima @kqadem Any news? |
I wanted to prototype earlier on and faced a similar issue. My temporary solution was to make my local server transform the css files into javascript that append a stylesheet in the const connect = require('connect');
const http = require('http');
const static = require('serve-static');
const transform = require('connect-static-transform');
const css = transform({
root: __dirname,
match: /(.+)\.css/,
transform: (path, content, send) => {
const c = `
const css = document.createElement('style');
css.type = "text/css";
css.textContent = \`${content}\`;
document.head.appendChild(css);
`;
send(c, {'Content-Type': 'application/javascript'});
},
});
const app = connect().use(css).use(static(__dirname));
http.createServer(app).listen(8000); |
Didn't realize I'm still subscribed to this. Never intended to participate in such discussion. Personally I don't even know where the problem is. If you want ESM spec compliance, you can either
thats it from your side as the 'providing side'. The question of how the consumer works with it in the end shouldn't be your concern as long as your stuff comply the specs (imho) |
Hello, is there any update on distributing a browser/spec-friendly ESM build? I think the suggestions given above are all quite reasonable:
Browser-friendly ES modules with minimal side-effects per module are an incredibly useful tool for publishing future-proof packages. As of now, I can't really ship a browser-runnable package without forcing the user into webpack or parcel. Alternatively, Rollup support would also make this transformation much easier. |
I can't believe we are still not on standard here. |
I forgot about Monaco not being standards compliant here after being away from two years, and hit this roadblock again when trying to load code directly into a browser. Again, can the ESM distribution be renamed to "webpack" or something? It's just misleading at this point. If the library really is distributed as modules then typing Then, can the CSS just be built and distributed a different way? Many libraries that use standard modules these days publish CSS inside of JS modules, sometimes via a build step. Vexflow and CodeMirror 6 are two I've seen recently. Everything made with LitElement works this way. The benefit is that the CSS is part of the library's module graph and you don't need any bundler to get the right files loaded. |
For anyone else struggling with this: yes. This library is not exported as a valid ESM module. If you need to use it on a real-life project (specially if you rely on popular abstractions like create-react-app or next-js), it needs to be transpiled and loaded with a separate webpack rule. Here's a few things that worked on my current stack, but each toolchain will have it's entry points to allow webpack tweaks (or the
// pseudo-code from the docs here:
// https:/react-monaco-editor/react-monaco-editor#using-with-webpack
// Specify separate paths
const path = require('path');
const APP_DIR = path.resolve(__dirname, './src');
const MONACO_DIR = path.resolve(__dirname, './node_modules/monaco-editor');
// pass webpack module.rules
{
test: /\.css$/,
include: APP_DIR,
use: [{
loader: 'style-loader', // or whatever you use
}, {
loader: 'css-loader', // or whatever you use
options: {
modules: true,
namedExport: true,
},
}],
}, {
test: /\.css$/,
include: MONACO_DIR,
use: ['style-loader', 'css-loader'],
},
, {
test: /\.ttf$/,
include: MONACO_DIR,
use: ['file-loader'],
}
import dynamic from 'next/dynamic'
const MonacoEditor = dynamic(import('react-monaco-editor'), { ssr: false })
<MonacoEditor ... />
Hope this list of hints helps others trying to consume it on their projects... but also highlights how much effort/knowledge/fiddling is needed to actually use the library :) |
Reiterating what @justinfagnani has said above; calling this |
https://web.dev/css-module-scripts/ indicates a possible way forward: import sheet from './styles.css' assert { type: 'css' };
document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet]; or the async variant const cssModule = await import('./style.css', {
assert: { type: 'css' }
});
document.adoptedStyleSheets = [cssModule.default]; |
@alexdima does this mean you will change the imports to standard ones? |
@alexdima |
Checking in to raise awareness of this still being an issue and it rises to the surface for all Angular 14 users, as the latest release of Angular 14 has a significant change on this topic:
See also: angular/angular-cli#23273 |
For those of you ending up here finding a solution to have Monaco Editor ESM style work with Angular 14, this might help:
const webpack = require("webpack");
const path = require("path");
const MONACO_DIR = path.join(__dirname, "..", "node_modules/monaco-editor");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
include: MONACO_DIR,
use: ["style-loader", {
"loader": "css-loader",
"options": {
"url": false,
},
}],
},
],
},
}; |
@evtk thnx, but not working :(
"dependencies": {
|
Thanks for this. It's painful to need a custom webpack config, but it worked like a charm. However, I now have a bunch of nonsensical warnings in my Angular build, e.g.: Warning: /...../node_modules/monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css depends on '!../../../../../../../style-loader/dist/runtime/styleDomAPI.js'. CommonJS or AMD dependencies can cause optimization bailouts. The irony of it complaining about these being "CommonJS or AMD dependencies" is not lost on me. I don't see how to disable the warnings though, given that they are coming from style-loader itself. Whitelisting style-loader in angular.json using |
@codeStryke without diving too much into that bundle: would it be possible to use Monaco without all the needed webpack config? I would love to remove all that custom config and the need for the custom builder for our Angular app. |
@evtk You can also use "prebuild" and then import as ES module. Just use this |
Thanks for the input @codeStryke and @bultas. The thing is I need to apply an additional worker on it and so far I haven't managed to apply that additional configuration to the monaco-editor and then export it to be used as ES module. |
I managed to build an ESM library out of the monaco-editor which includes a default configuration for YAML (only). It is pretty tailor made (added specific exports in the module), but thought it was worth posting here to help others. https:/evtk/monaco-editor-yaml-esm For those coming here, looking for an answer how to use the Monaco Editor with Angular. Besides that webpack based solution I posted earlier on, you can also use this package or your own fork of it. It removes the need to use custom angular builders, which i wanted to get rid of. Instead of installing the monaco-editor use the bundle I created and make sure to add the following glob to your
|
For those of us that use web-dev-server and typescript, what is the suggested solution. I'm currently running into this problem with this change: The challenge with monaco-component is that you lose the typings. |
@poucet Web Dev Server can accept arbitrary rollup plugins to serve these kinds of things, but the problem is that I'm not sure how monaco expects those CSS imports to be handled, hence why monaco should remove them from their distribution bundle. Here is an example of using WDS + a random CSS rollup plugin I found (not sure if this is how monaco expects it to be used): https://stackblitz.com/edit/node-tfl4jq?file=types.d.ts But, doing this compilation at serve time is probably not what you want because it can cause server latency. To make TS not crash, you should include a |
As Import Attributes are now at stage 3 (again), would it be possible to switch monaco to use valid ES6 Code? |
related to #4175 |
Another option for Angular, if you don't want to use the custom webpack builder listed above, is to do something like this somewhere in the build or postinstall:
And then add this to your global styles list in angular.json:
This works better for my particular use case, where I am publishing a reusable monaco-editor component. I've added the npx script to the component library's postinstall, and I no longer have to force users of the component/library to use the custom webpack builder. It's a bit ugly, but so are the .css imports being removed! |
@neodescis did you ever find a solution for those warnings? |
@lppedd , if you use the solution I posted just above, instead of the custom webpack builder, you shouldn't see any warnings. |
I'm not sure if it can work for my requirement: I need to have the smallest bundle possible. OT for posterity. I had to disable Webpack caching to get the plugin's loader to work.
|
In the ESM (EcmaScript Modules) version, css files are being imported like:
I have looked into the ECMA-262, TC39 proposals etc. but nowhere I could find that importing CSS files or other assets is allowed this way. Do any browsers support importing CSS files that way? Do I miss anything obvious? To me the ESM version is not ESM ;).
The text was updated successfully, but these errors were encountered: