Rollup imported css in a webcomponent - javascript

I am creating simple webcomponent now I want to import css , I found a method using adpotedstylesheet.
Here is how I import it my webcomponet
import sheet from './styles/swal.css' assert { type: 'css' };
class Demo extends HTMLElement{
constructor() {
this.attachShadow({ mode: "open" });
this.shadowRoot.appendChild(Demo.content.cloneNode(true));
document.adoptedStyleSheets = [sheet];
this.shadowRoot.adoptedStyleSheets = [sheet];
}
}
window.customElements.define("demo-component", Demo);
and here is my rollup settup for bundling my component
import summary from "rollup-plugin-summary";
import { terser } from "rollup-plugin-terser";
import resolve from "#rollup/plugin-node-resolve";
import replace from "#rollup/plugin-replace";
import postcss from "rollup-plugin-postcss";
import { eslint } from "rollup-plugin-eslint";
import babel from "rollup-plugin-babel";
import { uglify } from "rollup-plugin-uglify";
import commonjs from 'rollup-plugin-commonjs';
export default {
input: "index.js",
output: {
file: "dist/index.js",
format: "esm",
},
onwarn(warning) {
if (warning.code !== "THIS_IS_UNDEFINED") {
console.error(`(!) ${warning.message}`);
}
},
plugins: [
postcss({
plugins: [],
extensions: [".css"],
}),
resolve({
jsnext: true,
main: true,
browser: true,
}),
commonjs(),
eslint({
exclude: ["src/styles/**"],
}),
babel({
exclude: "node_modules/**",
}),
terser({
ecma: 2017,
module: true,
warnings: true,
mangle: {
properties: {
regex: /^__/,
},
},
}),
summary(),
replace({
"Reflect.decorate": "undefined",
preventAssignment: true,
ENV: JSON.stringify(process.env.NODE_ENV || "development"),
}),
process.env.NODE_ENV === "production" && uglify(),
],
};
Now when i run npm run buil I get the following error.
[!] (plugin commonjs) SyntaxError: Unexpected token (3:38)`
What am I doing wrong here ???

Currenly, Rollup doesn't support import assertions. There is open issue for Rollup to address it. There is an experimental Rollup plugin that supports this but it seems to have some issues.
Another option you can try is to use rollup-string-plugin. You can use it to read CSS file as a string and then build your constructible stylesheets and assign it to adoptedStyleSheets property as explained here for Webpack. Following is one example of doing it..
// Read SCSS file as a raw CSS text
import styleText from './my-component.css';
const sheet = new CSSStyleSheet();
sheet.replaceSync(styleText);
// Custom Web component
class FancyComponent1 extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
// Attaching the style sheet to the Shadow DOM of this component
shadowRoot.adoptedStyleSheets = [sheet];
shadowRoot.innerHTML = `
<div>
<p>Hello World</p>
</div>
`;
}
}
Side note: With Webpack, you can use raw-loader.

Be aware that adoptedStyleSheets is currently not supported by Safari on Mac and iOS. But, Rollup might handle this for you - I don't know.
Another solution is to check out:
https://www.npmjs.com/package/csshtml-module
This CLI tool can be set up to let you automatically compile CSS/HTML to native JS modules.
I created that CLI tool to tackle this issue. It might not be for everyone - but maybe it resonate with you.

Related

Webpack bundled library does not compile in React

I'm trying to bundle a standalone library with Webpack (v5) and use it in my React application.
The webpack.config.js file is pretty straightforward:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './TestWebpack.js',
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
output: {
filename: 'widgets.bundle.js',
path: path.join(__dirname, '..', 'ClientApp', 'src', 'dynamicBundles'),
library: {
name: 'widgets',
type: 'umd',
umdNamedDefine: true,
}
},
externals: {
'react': {
'commonjs': 'react',
'commonjs2': 'react',
'amd': 'react',
'umd': 'react'
},
'react-dom': {
'commonjs': 'react-dom',
'commonjs2': 'react-dom',
'amd': 'react-dom',
'umd': 'react-dom'
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-react'
],
}
}
},
]
},
};
The TestWebpack.js file is also very simple:
import React from 'react';
export default function TestWebpack(){
return (
<div>Test</div>
)
}
But when I compile it with Webpack and use it in my React application like this:
import React from 'react'
import { useEffect } from 'react'
import * as Widgets from '../dynamicBundles/widgets.bundle'
export default function TestUsingWebpack(){
useEffect(() => {
console.log('Object.keys(Widgets) - ', Object.keys(Widgets));
}, []);
return <div>Test</div>
}
I get the following errors:
Line 12: 'define' is not defined no-undef
Line 13: 'define' is not defined no-undef
Line 18: Unexpected use of 'self' no-restricted-globals
I can't figure out how to solve this. I see in the bundled file that in these lines an undefined variable 'define' is used. I saw in other answers that people put lines at the start to define it properly, but this bundle may change frequently so it's not an answer.
Maybe there's something wrong with my Webpack config file? I'm new to this and tried following the newest articles and Webpack documentation about standalone library but it's still not working.

How to configure Relay.JS in Vite?

I'm trying to migrate my React project from CRA to Vite, this is my vite.config.js:
import { defineConfig } from 'vite'
import react from '#vitejs/plugin-react'
import envCompatible from 'vite-plugin-env-compatible'
import relay from "vite-plugin-relay"
import macrosPlugin from "vite-plugin-babel-macros"
import path from 'path';
import fs from 'fs/promises';
export default defineConfig({
resolve: {
alias: {
'~': path.resolve(__dirname, 'src'),
'#material-ui/core': path.resolve(__dirname, 'node_modules/#material-ui/core')
}
},
esbuild: {
loader: "tsx",
include: /src\/.*\.[tj]sx?$/,
exclude: [],
},
optimizeDeps: {
esbuildOptions: {
plugins: [
{
name: "load-js-files-as-jsx",
setup(build) {
build.onLoad({ filter: /src\/.*\.js$/ }, async (args) => ({
loader: "tsx",
contents: await fs.readFile(args.path, "utf8"),
}));
},
},
],
},
},
define: {
global: {},
},
plugins: [
envCompatible(),
react(),
relay,
//macrosPlugin(),
],
})
My GraphQL query files are like this:
import graphql from 'babel-plugin-relay/macro'
const getQuery = () => graphql`
query UserQuery($id: ID!) {
user(id: $id) {
id
fullName
}
}
`
export default getQuery
When I tried to run the project in dev mode (command $ vite), I got this error:
So I did some search and replaced vite-plugin-relay to vite-plugin-babel-macros like this:
// others import
import relay from "vite-plugin-relay"
import macrosPlugin from "vite-plugin-babel-macros"
export default defineConfig({
// configs like bellow
plugins: [
envCompatible(),
react(),
//relay,
macrosPlugin(),
],
})
So I started to get a new error:
How can I configure Relay to work on Vite.JS?
Might be a bit late, but the issue has been fixed in Relay#13 and you can find some workarounds in this thread for older versions of Relay :
https://github.com/facebook/relay/issues/3354
You can also try adding the option eagerEsModules: true to your relay babel plugin configuration.
Unless you have some specific usecase that requires the use of babel-plugin-relay, your issue should be resolved if you change your imports from
import graphql from 'babel-plugin-relay/macro'
to
import { graphql } from "react-relay";
You should only need the relay vite plugin at that point, and can remove vite-plugin-babel-macros
There's a few things wrong with your setup.
1. Don't use vite-plugin-babel-macros:
Use #vitejs/plugin-react instead.
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
import relay from "vite-plugin-relay";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [relay, react({
babel: {
plugins: ['babel-plugin-macros']
},
})],
});
You can probably get it to work with vite-plugin-babel-macros, but the later is an official plugin.
2. Don't use 'babel-plugin-relay/macro':
Use the following instead:
import { graphql } from "react-relay";
It's unclear to me why the official docs suggest using babel-plugin-relay/macro, but that just doesn't work.
3. Configure relay.config.js correctly:
{
"src": "./src",
"language": "typescript",
// Change this to the location of your graphql schema
"schema": "./src/graphql/schema.graphql",
"exclude": [
"**/node_modules/**",
"**/__mocks__/**",
"**/__generated__/**"
],
"eagerEsModules": true
}
In particular, make sure you use language: typescript and eagerEsModules.
4. Sample repository
I wrote a sample repository showing how to properly configure React Relay with Vite.js and TypeScript, you can find it here.

Rollup + React 17 with new JSX Transform - "React is not defined"

I'm trying to prototype a microfrontend architecture with Rollup and a couple of create-react-app applications. However when I locally yarn link my external app with the container app, I run into the following error:
ReferenceError: React is not defined
23500 | return /#PURE/React.createElement("div", {
| ^ 23501 | id: "container",
23502 | className: "flex flex-col h-screen"
23503 | }, /#PURE/React.createElement(BrowserRouter, null, /#PURE/React.createElement(Header, {
I think it's because we're not importing React at the top of every component/file because of React 17's new JSX Transform allowing you to not have to do that. I'd really like to be able to build our micro frontend package without having to import React in every file, is there a way to do this?
Here is the rollup.config.js:
import babel from 'rollup-plugin-babel';
import commonjs from '#rollup/plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
import resolve from '#rollup/plugin-node-resolve';
import image from '#rollup/plugin-image';
import visualizer from 'rollup-plugin-visualizer';
import includePaths from 'rollup-plugin-includepaths';
import replace from '#rollup/plugin-replace';
import pkg from './package.json';
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
export default {
input: './src/App.jsx',
output: [
{
file: pkg.main,
format: 'cjs',
},
{
file: pkg.module,
format: 'esm',
},
],
plugins: [
external(),
postcss(),
resolve({
mainFields: ['module', 'main', 'jsnext:main', 'browser'],
extensions,
}),
image(),
visualizer(),
includePaths({ paths: ['./'] }),
replace({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
babel({
exclude: 'node_modules/**',
plugins: [
[
'module-resolver',
{
root: ['src'],
},
],
],
presets: ['#babel/preset-react'],
}),
commonjs(),
],
};
In tsconfig.json, add the following code
{
"compilerOptions": {
"jsx": "react-jsx",
}
}
Fixed this by adding { runtime: "automatic" } to the #babel/preset-react preset.
From the preset-react runtime docs:
automatic auto imports the functions that JSX transpiles to. classic does not automatic import anything.
Also mentioned in the React post about the new JSX transform:
Currently, the old transform {"runtime": "classic"} is the default option. To enable the new transform, you can pass {"runtime": "automatic"} as an option to #babel/plugin-transform-react-jsx or #babel/preset-react
Here's a sample:
{
// ...
plugins: [
// ...
babel({
// ...
presets: [
// ...
["#babel/preset-react", { runtime: "automatic" }],
]
})
]
}

#storybook/angular cannot load scss file on stories index

I have been trying to use storybook for my angular project and I use this guide https://storybook.js.org/basics/guide-angular/
I use the recommended config for webpack for sass loader for scss files and the scss file related to the project works fine, but if I import a scss file in the stories index.ts file, this file it is not loaded.
stories/index.ts
import { storiesOf } from '#storybook/angular';
import { action } from '#storybook/addon-actions';
import { VideoPosterComponent } from '../src/app/modules/ui-common/video-poster/video-poster.component';
//This scss it is not loaded
import '../src/styles.scss';
storiesOf('Video Poster component', module)
.add('Video Poster with author data', () => ({
component: VideoPosterComponent,
props: {
title: "Cinemagraph With Custom title",
subtitle: "This is a custom subtitle!"
}
}))
.add('Video Poster without author data', () => ({
component: VideoPosterComponent,
props: {}
}));
.storybook/webpack.config.js (recommended in here --> https://storybook.js.org/basics/guide-angular/#configure-style-rules)
const genDefaultConfig = require('#storybook/angular/dist/server/config/defaults/webpack.config.js');
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
// Overwrite .css rule
const cssRule = config.module.rules.find(rule => rule.test && rule.test.toString() === '/\\.css$/');
if (cssRule) {
cssRule.exclude = /\.component\.css$/;
}
// Add .scss rule
config.module.rules.unshift({
test: /\.scss$/,
loaders: ['raw-loader', 'sass-loader'],
});
return config;
};
And, the scss file for my component was loaded without problems
src/app/modules/ui-common/video-poster/video-poster.component.ts
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-video-poster',
templateUrl: './video-poster.component.html',
styleUrls: ['./video-poster.component.scss'] // this were loaded without problems
})
export class VideoPosterComponent implements OnInit {
private hostUrl = 'https://s3-eu-west-1.amazonaws.com/video.gallereplay.com/portfolio/clients';
private baseUrl = `${this.hostUrl}/jaegermeister/Cinemagraph_plain/1920x1080`;
#Input()
public videoUrls = {
poster: `${this.baseUrl}/cinemagraph.jpg`,
mp4: `${this.baseUrl}/cinemagraph.mp4`,
webm: `${this.baseUrl}/cinemagraph.webm`,
}
#Input() public title = 'Custom Cinemagraph Productions';
#Input() public subtitle = 'Exclusive Content for Businesses';
constructor() { }
ngOnInit() {
}
}
Repository:
https://github.com/gpincheiraa/storybook-components-sample
run npm install && npm run storybook for check storybook running.
What I am doing wrong??
I assume that, like me, you're looking for a way to load global styles from SASS files into an Angular Storybook. I know it's been a while since you asked, but I came across this solution while searching for a way to accomplish this: https://github.com/storybookjs/storybook/issues/6364#issuecomment-485651328.
Basically, you can load your global styles in the Storybook config file. However, you need to use inline webpack loaders in the import path so Storybook will load them properly.
import '!style-loader!css-loader!sass-loader!../src/styles.scss';
That did the trick for me. In the end I didn't have to bother with the custom webpack config. Hopefully that solves your problem!
You are trying to import an scss file from your typescript. You must include it from your scss.
Please remove :
//This scss it is not loaded
import '../src/styles.scss';
In your scss file add :
#import "styles.scss";
In you angular.json add :
"styles": [
"src/styles.scss",
],
"stylePreprocessorOptions": {
"includePaths": [
"src/" // maybe not required in your case
]
},
In you .storybook/webpack.config.js please try :
const path = require("path");
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loaders: ["sass-loader"],
include: path.resolve(__dirname, "../src/")
}
]
}
};
Otherwise there is the possibility to add an alias as Xdecus said here https://github.com/storybooks/storybook/issues/3814#issuecomment-401756776
const path = require('path');
module.exports = {
resolve: {
alias: {
styles: path.resolve(__dirname, '../src/')
}
}
};
All style imports must be in Component metadata (specifically in styles or styleUrls field). You're trying to import style file as js file, which is wrong.

Inversify.js - Reflect.hasOwnMetadata is not a function

I'm trying out Inversify.js for a Typescript application I'm using. Right now, there is no framework involved, so it's pure ES2015.
I'm trying to follow along the example in the main page, but I'm being hit with:
"Reflect.hasOwnMetadata is not a function" when I try to run it in the browser.
I'm using Webpack as package bundler.
Here is my folder structure:
Here is the main app.ts file:
/// <reference path="../typings/index.d.ts" />
/// <reference path="./domain/abstract/match.interface.ts" />
import kernel from "../inversify/inversify.config.ts";
import {symbols} from "../inversify/symbols.ts";
var ninja = kernel.get<INinja>("INinja");
ninja.fight();
ninja.sneak();
interfaces.d.ts:
interface INinja {
fight(): string;
sneak(): string;
}
interface IKatana {
hit(): string;
}
interface IShuriken {
throw();
}
inversify.config.ts
/// <reference path="../node_modules/inversify/type_definitions/inversify/inversify.d.ts" />
/// <reference path="../node_modules/reflect-metadata/reflect-metadata.d.ts" />
/// <reference path="inversify.ts" />
import {Kernel} from "inversify"
//import {MatchHub} from "../app/components/Hubs/match/match-hub.component.ts";
//import {symbols} from "./symbols.ts";
import {Ninja, Katana, Shuriken} from "./inversify.ts";
var kernel = new Kernel();
kernel.bind<INinja>("INinja").to(Ninja);
kernel.bind<IKatana>("IKatana").to(Katana);
kernel.bind<IShuriken>("IShuriken").to(Shuriken);
export default kernel;
symbols.ts:
export const symbols = {
Match : Symbol("Match")
}
tsconfig.json:
{
"compilerOptions": {
"noImplicitAny": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"removeComments": true,
"sourceMap": true,
"target": "es5"
},
"exclude": [
"node_modules",
"bower_components",
"wwwroot"
]
}
Webpack.config.js:
module.exports = {
entry: './app/app.ts',
output: {
filename: '../Scripts/app/app.js'
},
resolve: {
extensions: ['', '.Webpack.js', '.web.js', '.ts','.js', '.tsx']
},
module: {
loaders: [
{
test: /\.ts?$/,
exclude: /(node_modules|bower_components)/,
loader: 'ts-loader'
}
]
},
watch: true
}
Firefox Console Error:
Webpack output:
When I tried to install Inversify the following warnings popped up:
Is it a bug? Or am I doing something wrong? Thanks!
PS: Tried following the sample files, but I couldn't understand anything!
I come from ASP.NET MVC 5 with Ninject so I can relate for most of the syntax.
It seems you will need to include the reflect-metadata package. Try adding an import to it in inversify.config.ts by doing:
import "reflect-metadata";
May be a silly thing to point out, I ran into a the same issue but it was because of the order of imports.
Its unlikely to be the case for any other imports but in case of reflect-metadata it has to be imported before any classes that use it.
import { Container } from "inversify";
//reflect-metadata should be imported
//before any interface or other imports
//also it should be imported only once
//so that a singleton is created.
import "reflect-metadata";
import Battle from "./interfaces/battle";
import EpicBattle from "./interfaces/epic_battle";

Categories

Resources