Add CSS styles directly into the shadow-root instead of the head tag | Vue.js and Webpack

Currently, I'm developing a widget that can be embedded on websites using Vue.js along with vue-custom-element. Everything was going well until I encountered an issue.

The problem arises when trying to integrate a component (along with its CSS) from a package such as vue-number-input. Despite my attempts to keep the CSS encapsulated within the shadow root, it ends up being injected into the head of the webpage.

You can observe this behavior in this screenshot, where the CSS from the number input package is placed in the head instead of the shadow root.

I have made all necessary adjustments to ensure that the application functions properly within the shadow root.

To further investigate this issue, I have shared my vue.config.js, my main.js file (where I register the custom element), and my component (where I import the package's component).

If anyone has insights on how to resolve this issue or if it is even feasible, please share your expertise.

Answer №2

After conducting extensive research to find a method that would lazy-load our styles into the shadow-root, we came up empty-handed. Ultimately, we had to settle for a less than ideal solution, which meant loading all the styles on initial load.

Note: While this workaround works for QA and production environments, during development, the styles will still be loaded within the head of the page. It's important to ensure that no other styles conflict with this setup.

Our approach to achieving this was as follows:

// vue.config.js

const webpack = require('webpack');

module.exports = {
  configureWebpack: {
    // ...
    plugins: [
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1,
     }),
   ],
 },
 chainWebpack: (config) => {
   config.optimization.delete('splitChunks');
 },
};
// main.js

import createStyleLink from '@/helpers/createStyleLink';

// ...

const options = {};

// Enabling shadow root for the production build
if (process.env.NODE_ENV === 'production') {
  options.shadow = true;
  options.beforeCreateVueInstance = (root) => {
    const rootNode = root.el.getRootNode();
    if (rootNode instanceof ShadowRoot) {
      root.shadowRoot = rootNode;
    } else {
      root.shadowRoot = document.head;
    }
    // After deployment, this code will create a style link and place it inside the shadow root. 
    // Ideally, a CDN should be used for this purpose.
    createStyleLink(rootNode, `${process.env.VUE_APP_URL}/css/app.css`);
    return root;
  };
}

// ...

Vue.customElement('widget', App, options);
// createStyleLink.js

export default function (node, url) {
  const link = document.createElement('link');
  link.href = url;
  link.type = 'text/css';
  link.rel = 'stylesheet';
  node.appendChild(link);
}

I hesitate to label this as a perfect solution, as it is more of a makeshift fix for the issue at hand.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshooting a jQuery carousel: How can I prevent the thumbnails from automatically moving forward?

I am currently modifying a carousel where the thumbnails are moving out of frame. I need assistance in keeping them stationary, except for the blue thumbnail highlighter. To better illustrate the issue, I have created a jsFiddle here: http://jsfiddle.net ...

Why isn't the show/hide feature in Jquery functioning properly?

I have a div that needs to be displayed after hovering over another element. These elements are not within the same div. The popup info should appear when an icon with the class .option_36_124 is hovered over. $(".option_36_124").hover(function(){ $(& ...

Alert: Parser error in JSONP!

$.ajax({ type: "GET", dataType: "jsonp", jsonpCallback: "jsoncallback", //async: true , data: { // some other data here }, url: "http://mywebsite.com/getRequest.php", success: function(response ...

Fetching Data from Response Headers in Angular 4.3.3 HttpClient

(Text Editor: Visual Studio Code; TypeScript Version: 2.2.1) The main objective here is to fetch the headers of the response from a request Let's consider a scenario where we make a POST request using HttpClient within a service: import { Injec ...

A mistake has been identified: The object could potentially be 'null'. TS2531 for window.document

This is my first time integrating TypeScript into my project. When attempting to access something using window.document.getElementById(), I keep encountering the error: Type error: Object is possibly 'null'. TS2531 I've looked online for ...

Access the Express server by connecting to its IP address

Is it feasible to connect to an express server using the server's UP address? If so, how would one go about doing this? (Examples of code snippets would be greatly appreciated) ...

Exploring the possibilities of JavaScript within the IntelliJ REST client

I've delved into the extensive documentation provided by JetBrains on their HTTP Client and how to incorporate requests using files with a .http extension. The challenge I'm facing involves utilizing a function from a separate .js file within on ...

What is the best way to include JSON values for specific keys using JavaScript, jQuery, or AngularJS?

Below is a sample of the json: var json = var data = [{ "a": 150 }, { "a": 50 }, { "b": 100 }, { "b": 25 }]; I aim to combine the values of "a" and "b" in a new finaljson(the desired output json), like so: var finaljson = [{ "a": 200 ...

Extract core object from array of objects with lodash or javascript

In my code, I have an array of objects that each contain a base object with a set of values. My goal is to remove the base object from all the data and achieve the Expected result shown below. Here is an example of the array: [ { "100": { ...

What is the best way to create a "tile-based board" for this game?

I am working on a project to create a board made up of tiles, but I am facing difficulty in filling up the entire board area. Currently, I have only managed to create 1 column of the board, as shown in the image. Can someone guide me on how to fill the ent ...

Guide on creating a Docker image from a Vue.js application and deploying it to a Nexus repository using GitLab's CI/CD pipeline

I am currently working on a Vuejs application that needs to be built in order to push into Nexus as a Docker image. All the Vuejs contents are stored on a GitLab repository. The pipeline consists of these stages: setup (retrieve information from pipeline ...

The error message "ng: command not found" popped up despite successfully installing the latest @angular/cli using npm linking

Here is the information about my current setup: Node version: v10.15.3 NPM version: 6.4.1 I attempted to run the following command: Command: npm i -g angular/cli An error occurred while executing: npm ERR! /usr/local/bin/git ls-remote -h -t ssh:// ...

Utilizing Vue and Vuex to execute Axios operations within a store module

Currently, I am developing an application in Vue that utilizes Vuex for state management. For CRUD operations on the data, I have implemented Axios. The issue arises when, for example... I make a POST request to my MongoDB database through an Express ...

Adjusting the position of a stationary element when the page is unresponsive and scrolling

Managing a large web page with extensive JavaScript functionality can be challenging, especially when dealing with fixed position elements that update based on user scroll behavior. A common issue that arises is the noticeable jumping of these elements whe ...

Vue - Ways to securely integrate Firebase config data into main.js

Currently, I am utilizing firebase within a Vue application with the following configuration: var firebaseConfig = { apiKey: "", authDomain: "", databaseURL: "", projectId: "", storageBucket: "", appId: "", measurementId: " }; ...

Dropdown menu not populating with options in AngularJS ngOptions

It's puzzling to me why the dropdown menu is not being populated by ng-options. Despite JSON data being returned from the service and successfully logged in the controller, ng-options seems to be failing at its task. <tr class="info"> <td ...

Can you provide guidance on decompressing SVGZ files using JavaScript?

I'm currently working on implementing a high-resolution world map using SVGZ instead of the standard SVG format, aiming to provide my users with a more intricate and detailed visualization. Although I have experimented with utilizing js-deflate to de ...

There is a potential risk of NextResponse.json file compromising the integrity of JSON

Running nextjs 13.5.3 and implementing an API route handler under /app This route handler mainly fetches data from a CMS and then returns the response. The IDs on the client side are hashed, so one of the functions is to unhash the IDs from a request and ...

JavaScript Function for Finding the Time Difference Between Two Dates (in Years, Days, Hours, or Less than One Hour)

I need to calculate the time difference between 2 dates and display it. If the difference is greater than a year, show the number of years only. If it's more than a day, show the number of days. If it's less than a day, show the number of hours. ...

What methods can be used to identify the pattern entered by the user for data types such as `Int`, `VarChar`, `

I have a dropdown menu containing data types. There is also a text box for entering Regex patterns. If "/test/" is entered in the textbox or "Int" is selected from the dropdown, then it's an incorrect pattern. If "/[0-9]/" is entered in the ...