Self Hosted Font in material-ui theme component library not working - reactjs

I'm building a component library to sit alongside some react apps within a monorepo, library is currently being consumed by app1 and displaying components exported from the library just fine.
The library is based on masterial ui and themed. I'm using storybook and rollup for documentation and bundling, which means having to cater to both webpack (for storybook) and rollup for the actual library build.
.storybook/main.js:
module.exports = {
stories: ['../src/**/**/*.stories.mdx', '../src/**/**/*.stories.tsx'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'storybook-addon-designs'
],
webpackFinal: (config) => {
// Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test.test('.svg')
)
fileLoaderRule.exclude = /\.svg$/
config.module.rules.push(
{
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('#svgr/webpack')
},
{
test: /\.(woff|woff2|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: require.resolve('file-loader'),
options: {
// Limit at 50k. Above that it emits separate files
limit: 50000,
// Output below fonts directory
name: '[name].[ext]',
outputPath: '../src/build/fonts/'
}
}
]
}
)
return config
}
}
And my rollup.config.js:
import commonjs from '#rollup/plugin-commonjs'
import resolve from '#rollup/plugin-node-resolve'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
import typescript from 'rollup-plugin-typescript2'
import svgImport from 'rollup-plugin-svg-hyperscript'
import url from '#rollup/plugin-url'
import packageJson from './package.json'
export default {
input: './src/index.ts',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true
},
{
file: packageJson.module,
format: 'esm',
sourcemap: true
}
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript(),
svgImport(),
url({
include: ['**/*.woff', '**/*.eot'],
name: '[name].[ext]'
})
]
}
It should be noted that I have an Icon component that works with SVGS being bundled with rollup and displaying in storybook perfectly.
Font index:
import soehneWebKraftigWoff from './soehneWebKraftig.woff'
import soehneWebKraftigEot from './soehneWebKraftig.eot'
import soehneWebLeichtWoff from './soehneWebLeicht.woff'
import soehneWebLeichtEot from './soehneWebLeicht.eot'
export const fonts = {
soehneWebKraftigWoff,
soehneWebKraftigEot,
soehneWebLeichtEot,
soehneWebLeichtWoff
}
MuiCssBaseline:
import { fonts } from '../../fonts'
export const soehneWebKraftig = {
fontFamily: 'SoehneWebKraftig',
fontStyle: 'normal',
fontWeight: 400,
src: `url(${fonts.soehneWebKraftigWoff}) format('woff')`
}
export const MuiCssBaseline = {
'#global': {
'#font-face': [soehneWebKraftig]
}
}
The override is being indexed and exported from a folder called 'overrides' so this is my theme file:
import { createTheme } from '../../themeUtility'
import { rootPalette } from './rootPalette'
import { rootTypography } from './rootTypography'
import * as overrides from './overrides'
export const rootTheme = createTheme({
palette: rootPalette,
typography: rootTypography,
overrides: {
...overrides
}
})
The font is not loaded correctly in either storybook or in the rollup bundle (I can't see the font displaying correctly in app1 which consumes the bundle). I can see my font files renamed with hashes appearing in the rollup build output directory.
Any ideas?
Edit:
Fonts within build (but not inside the fonts folder?)

Related

Building styling in an Azure DevOps extension

My extension does not contain any css files when I build it and I don't know what makes it do that. I did not change the Common.tsx that was scaffolded. Neither my own styles or the Azure DevOps UI styling gets packaged or used by components.
Azure DevOps UI documentation says to do this:
https://developer.microsoft.com/en-us/azure-devops/develop/extensions
When consuming the 2.164.0 version or later of the azure-devops-ui package, extensions should import the Azure DevOps global styles in order to get the same look and feel (font family, font sizes, hyperlink treatment, etc.) of Azure DevOps pages. This can be done with the following import:
import "azure-devops-ui/Core/override.css";
This is already done in the Common.tsx by default however.
directory structure
src
│ Common.scss
│ Common.tsx
│
└───Components
└───RESTRequestButton
RESTRequestButton.html
RESTRequestButton.json
RESTRequestButton.scss
RESTRequestButton.tsx
webpack.config.js
const path = require("path");
const fs = require("fs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const entries = {};
const ComponentsDir = path.join(__dirname, "src/Components");
fs.readdirSync(ComponentsDir).filter(dir => {
if (fs.statSync(path.join(ComponentsDir, dir)).isDirectory()) {
entries[dir] = "./" + path.relative(process.cwd(), path.join(ComponentsDir, dir, dir));
}
});
module.exports = {
entry: entries,
output: {
filename: "[name]/[name].js"
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {
"azure-devops-extension-sdk": path.resolve("node_modules/azure-devops-extension-sdk")
},
},
stats: {
warnings: false
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.s[ac]ss?$/,
use: ["style-loader", "css-loader", "azure-devops-ui/buildScripts/css-variables-loader", "sass-loader"]
},
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.woff?$/,
use: [{
loader: 'base64-inline-loader'
}]
},
{
test: /\.html?$/,
loader: "file-loader"
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: "**/*.html", context: "src/Components" }
]
})
]
};
Common.tsx
import "azure-devops-ui/Core/override.css";
import "es6-promise/auto";
import * as React from "react";
import * as ReactDOM from "react-dom";
import "./Common.scss";
export function showRootComponent(component: React.ReactElement<any>) {
ReactDOM.render(component, document.getElementById("root"));
}
RESTRequestButton.scss
#import "node_modules/azure-devops-ui/Core/_platformCommon.scss";
RESTRequestButton.tsx (only how I import the styling and how I reference Common.tsx)
import "./RestRequestButton.scss";
import { showRootComponent } from "../../Common";
class RESTRequestButton extends React.Component<{}, {}> {
//a lot of code goes here
}
export default RESTRequestButton;
showRootComponent(<RESTRequestButton />);
The solution was to bump package versions. I set package style-loader to "^3.3.1" and it was fixed.

Error: Unexpected "<" in vite react in JS files

I am making a react app with vite instead of creat react app. When I use .jsx as suffix, it works fine. But when I use .js, throws hundreds of errors in my files, such as:
Layout.js:131:9: error: Unexpected "<"
I've read this in twitter from Evan You but is there no way?
As far as I used this code in vite.config.ts file:
import { defineConfig } from 'vite'
export default defineConfig(() => ({
esbuild: {
loader: 'jsx',
},
optimizeDeps: {
esbuildOptions: {
loader: {
'.js': 'jsx',
},
},
},
})
but it still didn't work! Could you possibly help me?
Try the below Vite configuration. This configuration worked for me. But in every js file, need to import React.
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import { resolve } from 'path';
import fs from 'fs/promises';
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
src: resolve(__dirname, 'src'),
},
},
esbuild: {
loader: 'jsx',
include: /src\/.*\.jsx?$/,
exclude: [],
},
optimizeDeps: {
esbuildOptions: {
plugins: [
{
name: 'load-js-files-as-jsx',
setup(build) {
build.onLoad(
{ filter: /src\\.*\.js$/ },
async (args) => ({
loader: 'jsx',
contents: await fs.readFile(args.path, 'utf8'),
})
);
},
},
],
},
},
plugins: [react()],
});

How do I make React components import extracted scss modules files with Rollup?

I'm making a React Component Library with Rollup with the following component setup:
//component A
import styles from './stylesA.module.scss'
const ComponentA = () => {
return(
<div className={styles.red}>Component A Styled</div>
)
}
export { ComponentA }
//stylesA.module.scss
.red {
color: red;
}
How do I configure Rollup so that my output components auto-import the generated .css files into my component? Note that I don't want the styles to be bundled into the .js files nor do I want to import the styles manually when I import the final package with import 'my-library/dist/stylesA.css'
My rollup.config.js looks like this for the moment:
// rollup.config.js
import resolve from '#rollup/plugin-node-resolve';
import babel from '#rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
import pkg from './package.json'
export default {
input: 'src/index.js',
output: [{
dir: './dist',
format: 'cjs'
}],
plugins: [
resolve(),
babel({
exclude: 'node_modules/**',
babelHelpers: 'bundled'
}),
postcss({
modules: true,
extract: true,
minimize: true
})
],
external: Object.keys(pkg.peerDependencies || {})
};

I18next and Webpack

I'm starting with Webpack and find problem with react i18next hook-useTranslation.
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
output: {
path: path.join(__dirname, '/dist'),
filename: 'index.bundle.js'
},
devServer: {
port: 3000,
host: 'localhost',
watchContentBase: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /nodeModules/,
use: {
loader: "babel-loader"
}
},
]
},
plugins: [
new HtmlWebpackPlugin(
{
template: './src/index.html'
}
),
new CopyPlugin({
patterns: [
{
from: path.join(__dirname, '/public') , to: path.join(__dirname, '/dist') // copy public folder, which contains locales for i18next
}
]
})
],
}
//i18next.js
import i18next from 'i18next'
import { initReactI18next } from 'react-i18next'
import HttpApi from 'i18next-http-backend'
i18next
.use(initReactI18next)
.use(HttpApi)
.init(
{
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
},
lng: "en_GB",
supportedLngs: ["en_GB","cs_CZ"]
})
export default i18next
//example.js
import React from 'react'
import { useTranslation } from 'react-i18next'
const Greeting = () => {
const { t } = useTranslation()
return (
<div>
{/* {t("common:greeting")} */}
</div>
)
}
export default Greeting
In browser nothing loads and in console print these errors
[WDS] Disconnected!
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: ...
I want have locales in public folder, not in assets, acording docs, it's better to keep code separated from translations. I tried everything, but I can't find any solution. Someone had a similar problem?
You didnt define a namespace, so loadPath: '/locales/{{lng}}/{{ns}}.json' wont find {{ns}}.json because you said that you have to find {t("common:greeting")}, the namespace that you are searching for is common .So in order to fix this change the loadPath: '/locales/{{lng}}/common.json'

Rollup React Library Output Multiple Build Folders?

I have created a React Library with rollup, however, I have a large number of components that get exported so the file size is relatively large.
So in a project where I import the library doing the following;
import { ComponentExampleOne, ComponentExampleTwo } from 'my-react-library';
It imports the whole index file outputted via rollup (including all other components and any 3rd party dependencies), so when a user first hits the page with the import above they need to download the whole file, which is a lot bigger than I would like it to be.
For the likes of lodash where I just want to access a single function and not the entire library, I would do the following;
import isEmpty from 'lodash/isEmpty';
I want to achieve similar functionality with rollup so I can do something like
import { ComponentExampleOne } from 'my-react-library/examples';
import { ButtonRed } from 'my-react-library/buttons';
So I only import what is exported in the index.js file within an examples and buttons folder with this is as my folder structure in my library.
my-react-library/
-src/
--index.js
--examples/
---ComponentExampleOne.js
---ComponentExampleTwo.js
---ComponentExampleThree.js
---index.js
--buttons/
---ButtonRed.js
---ButtonGreen.js
---ButtonBlue.js
---index.js
I have no idea to achieve this with rollup?
This is my current rollup.config.js
import babel from 'rollup-plugin-babel';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import filesize from 'rollup-plugin-filesize';
import localResolve from 'rollup-plugin-local-resolve';
import json from 'rollup-plugin-json';
import pkg from './package.json';
import externals from 'rollup-plugin-node-externals';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import image from 'rollup-plugin-inline-image';
import { terser } from 'rollup-plugin-terser';
const config = {
input: 'src/index.js',
watch: {
chokidar: {
usePolling: true,
paths: 'src/**'
}
},
output: [
{
file: pkg.browser,
format: 'umd',
name: 'Example'
},
{
file: pkg.main,
format: 'cjs',
name: 'Example'
},
{
file: pkg.module,
format: 'es'
},
],
external: Object.keys(pkg.peerDependencies || {}),
plugins: [
globals(),
builtins(),
externals(),
babel({ exclude: 'node_modules/**', presets: ['#babel/env', '#babel/preset-react'] }),
commonjs({
include: "node_modules/**",
namedExports: {
// left-hand side can be an absolute path, a path
// relative to the current directory, or the name
// of a module in node_modules
'node_modules/formik/node_modules/scheduler/index.js': ['unstable_runWithPriority'],
}
}),
peerDepsExternal(),
postcss({ extract: true }),
json({ include: 'node_modules/**' }),
localResolve(),
resolve({
browser: true,
dedupe: ['react', 'react-dom'],
}),
filesize(),
image(),
terser()
]
};
export default config;
Any help would be greatly appreciated.
You don't really need to do that if you use named exports and any modern bundler for building the app.
When Rollup detects you are not using some export it will be removed due to tree-shaking.
If you still want to do it pass an object with the different entries you want to the input option:
// ...
const config = {
input: {
examples: 'examples/entry/file.js',
buttons: 'buttons/entry/file.js'
},
// ...
}

Resources