I am trying to use defineCustomElement from Vue 3 to make Single File Components into custom elements.
However when I try to import a local stylesheet to the elements I get the error message: Refused to apply style from 'http://localhost:8081/assets/styles.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
I have created a basic Vue 3 project as per these instructions.
In my main.js file I have
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
import { defineCustomElement } from 'vue'
import HelloWorld from './components/HelloWorld.ce.vue'
const HelloWorldElement = defineCustomElement(HelloWorld)
customElements.define('hello-world', HelloWorldElement)
and in HelloWorld.ce.vue I have added:
<style>
#import url("https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta.2/css/bootstrap.css");
a {
color: #42b983;
}
#import '../assets/styles.css';
</style>
in the index file I have replaced the tapp with my component:
<hello-world></hello-world>
I've also created a basic CSS file under /src/assets/styles.css.
The bootstrap import works, as do CSS rules written directly within the <style> tags. However the imported local stylesheet will not work - I am sure I have the correct path. I have also tried importing it directly into main.js which also doesn't work.
Here is a Code Sandbox with the structure: https://codesandbox.io/s/staging-fire-lox4y9
Is there a way to have one stylesheet that works across multiple custom elements?
Related
I am trying to find the best solution for overriding the default 'Nova' theme used for Prime React. I am aware they have a theme designer available to purchase however I would ideally like to not use that.
Previously I was having a scss file with every tsx file in my react application. I was using lines such as -
.p-dropdown-trigger {
background-color: brown !important;
margin-left: 5px !important;
}
I was basically putting !important everywhere and it began to get very messy.
I have thought about commenting out the import for the Prime React theme in my index.tsx file
// import 'primereact/resources/themes/nova/theme.css';
And importing my own scss instead..
import './styles/Override.scss';
This makes the styling disappear completely and the page looks like it's purely html. I am thinking maybe I should copy all the code from the Nova theme file and then slowly start adjusting it in the override file.
Has anyone got a better way or any ideas?
Thanks
One option like you said is to copy all of the css over, and then hide their import. That may be more work than you need depending on what you're trying to do.
I would probably rather create an override.scss and specifically overwrite rules, which with scss nesting shouldn't get too crazy. But one tip to avoid using !important is to be more specific with the way you target HTML elements. For instance, if there is a CSS rule of
body header ul a { color: pink; }
then you can override a rule by being more specific and write:
body header ul li > a { color: blue; }
However if the rule you're trying to overwrite has !important in it, then you'll have to use !important in your new rule overwrite it.
Hmm, maybe I could help more if I had access to more code e.g. in codesandbox.io.
Do you try some modular CSS solution? Like Styled-jsx or Styled-Components?
If you would like to use styled-components, this answer could be helpful. PrimeReact and styled-component
A different solution could be, link the stylesheet with PrimeReact before your own stylesheet (inside of your HTML). This solution will require a deep analysis of the style implementation by the webpack.
Hope I could help somehow :)
Later CSS imports that come after the theme will override the templates as the last CSS rule has higher specificity (precedence) in CSS
In the following of a create-react-app index.tsx (typescript .js), index.css will override the imported prime themes but CSS imports in the child React "App" component will not override the theme because it is imported first. (And the last applicable CSS is the one that gets used unless you override with !important.)
import React from "react";
import ReactDOM from "react-dom";
import reportWebVitals from "./reportWebVitals";
import App from "./App";
import "../node_modules/primereact/resources/themes/saga-blue/theme.css";
import "../node_modules/primereact/resources/primereact.min.css";
import "../node_modules/primeicons/primeicons.css";
import "./index.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
You can make your React component's CSS (like "App") override the React Prime theming by importing the theme CSS as the first thing, then components after making their CSS later and higher precedence.
import "../node_modules/primereact/resources/themes/saga-blue/theme.css";
import "../node_modules/primereact/resources/primereact.min.css";
import "../node_modules/primeicons/primeicons.css";
import React from "react";
import ReactDOM from "react-dom";
import reportWebVitals from "./reportWebVitals";
import App from "./App";
import "./index.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
I'm trying to build a IIFE (immediately-invoked function expression) bundle using Rollup.
I would like to bundle all together my JS, CSS, and then some HTML which the Javascript depends on. Check this image to get an idea:
Is there a way to tell Rollup that my input (entry point) is seguro-vida-hipoteca.js, and have this file import my SCSS and HTML so it will be automatically injected when somebody uses my library?
That would be, the resulting CSS in the head, and the HTML to some div that I would expect to exist in the dom, or just at the end of body.
Is there a way to tell Rollup that my input (entry point) is seguro-vida-hipoteca.js?
Sure, that's what the input option is for.
Injecting Sass in the head is easily accomplishable with plugins such as rollup-plugin-postcss:
// rollup.config.js
import postcss from 'rollup-plugin-postcss';
export default {
// ...
plugins: [
postcss(),
],
}
import './style.scss'; // Now each stylesheet you import will
// be injected to <head>
About injecting/appending html, that is something you would normally do in your code and not through a plugin, although you can take advantage of Rollup to load template.html as a string (for example by using rollup-plugin-html):
import html from "rollup-plugin-html";
export default {
// ...
plugins: [
html({
include: "**/*.html",
}),
],
}
import template from './template.html';
document.querySelector('#mydiv').innerHTML = template;
Side note
This seems to be a good use case for WebComponents. More info here.
When developing my project, I look at others for an example. When I looking at Instagram website. I see the class name of html is change when user is login. May I know how to achieve that actually? As what I know, react only live in one of the div in html structure.
// This code will render a component in the html root.
ReactDOM.render(<App />, document.getElementById('root'));
// But how to serve a whole new html file in react
How to serve a whole new html file in react? Is it violate the concept of react?
HTML and Document body are outside the React realm of DOM handling. So you can use good old querySelector for setting the class names.
function LoginPage() {
useEffect(() => {
document.querySelector('html').classList.add('login-page');
}, []);
return (
// stuff
);
}
A handy package is the React ecosystem for these is React Helmet
import {Helmet} from "react-helmet";
function LoginPage() {
return (
<Helmet>
<html className="loginPage" {...anyOtherStuff} />
<body {...attributesOnBody} />
</Helmet>
);
}
If you would like to add nodes that are adjacent to the root node in the body or React provides you with a solution called Portals that can render anywhere.
For the abiity to change index.html itself, you would not be building yourself a SPA anymore which seems to be case to use React.
you should add a class to your html input to retrieve it.
Here is an exemple :
import React from 'react';
import ReactDOM from 'react-dom';
class X extends React.Component {
render() {
return <h2>TEXT HERE</h2>;
}
}
ReactDOM.render(<X/>, document.getElementById('root'));
React works in a way that attaches itself to some DOM element. In your case, you are attaching it to some element with id of root.
TLDR;
Your index.html will contain the code of your application inside the element with root id during the runtime in the browser. You can see it by inspecting it using browser developer tools.
Your <App /> is the root of your application and if you use dev tools of your browser and you inspect the DOM tree you will see components in there. They are just dynamically attached by React (ReactDOM) and React is in the control of when and how things are rendered.
If your components look something like:
import React from 'react';
function App() {
return <h1 className="title">Hello!</h1>;
}
In Dev tools your DOM structure will looks something like this:
<div id="root">
<h1 class="title">Hello!</h1>
</div>
Here you can see that you have element with root id that you attached your <App /> before and you can see the content of <App />, <h1 class="title" /> together with classes.
That is also how Instagram works and most of the single-page applications or SPAs in short.
There is also a possibility to render static version of your application.
I have a project where I am trying to apply different CSS styles for different layouts (which I am detecting by the URL, basically we have two different domain names). In the webpack.config file, I have excluded the style sheet used for the 2nd layout as it was loading all the CSS and putting it all in a single file during the build (which overrides the body color set for layout 1 with layout 2). But after excluding that particular CSS file it was not adding the style sheet back when viewing the 2nd website. Its a react app, and I am using an if condition to apply the style:
index.js file:
if (window.location.hostname.includes("website2")) {
require("./assets/css/style1.css");
require("./assets/css/style2.css");
} else {
require("./assets/css/style1.css");
}
webpack.config
module: {
test: /\.css$/,
exclude: /\style2.css$/,
....
}
I am new to webpack, so I am not sure if I should exclude the CSS file in this manner.
Webpack is a development / build tools. It only compiles source files. So your code won't work in runtime.
You should set a root css class as namespace/theme in each css file, then just change class name in body tag.
// note: scss styles
.style1 {
// style theme 1
}
.style2 {
// style theme 2
}
if (window.location.hostname.includes("website2")) {
body.classList.add("style1");
body.classList.add("style2");
}
else{
body.classList.add("style1");
}
What I want
Use the library HTML-GL inside a component in my Angular project (with the Ionic framework included).
What I got now
I included the library scripts inside my index.html, right above the polyfills.js - like this:
<!-- HtmlGL import -->
<script async src="assets/js/htmlgl.js"></script>
<script async src="assets/js/htmlGL_pulse.js"></script>
Right now the following web element works in index.html:
<html-gl>
<h1>This is an animated header</h1>
<html-gl>
What goes wrong
When I place the html above in a separate component I get the following error:
Uncaught Error: Template parse errors:
'html-gl' is not a known element
How can I make sure the component is aware of the `html-gl> tag?
To use dom elements which are not in the Angular registry you have to import the custom elements schema from angular core and append it to the schemas of your NgModule.
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';.