Css extraction issue with transpiled code
I have used my project (quickform-core) in another project and used css extraction without problems. But in a new project i am just hitting my head against the wall for hours now not able to figure out why.
my next.config.js
import { env } from "process";
import { withGriffelCSSExtraction } from '@griffel/next-extraction-plugin';
/** @type {import('next').NextConfig} */
const nextConfig = {
output: env.NODE_ENV === "production" ? 'standalone' : undefined,
compress: false,
experimental: {
instrumentationHook: true,
swcPlugins: [['fluentui-next-appdir-directive', { paths: ['@griffel', '@fluentui', '@eavfw'] }]],
},
transpilePackages: ["@fluentui/react-components", '@eavfw/quickform-core', '@eavfw/quickform-input-select', '@eavfw/query'],
webpack(config) {
config.module.rules.unshift({
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: '@griffel/webpack-loader',
},
],
});
// If your project uses TypeScript
config.module.rules.unshift({
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: '@griffel/webpack-loader',
options: {
babelOptions: {
presets: [
"next/babel"
]
},
},
},
],
});
return config;
},
};
export default withGriffelCSSExtraction()(nextConfig);
and i am getting the below error. I tried to identify the difference between my working project and the new project, but so far they are very similar.
Any hint to help me find the root cause would be nice.
@eavfw\quickform-core is basically a bunch of typescritp files distributed by npm
./src/components/quickform/GroupOnlineQuickform.tsx
C:\dev\go\qp\node_modules\@eavfw\quickform-core\src\index.ts:1
(function (exports) { export * from "./components";
^^^^^^
SyntaxError: Unexpected token 'export'
at new Script (node:vm:117:7)
at Module.evaluate (C:\dev\go\qp\node_modules\@linaria\babel-preset\lib\module.js:280:20)
at require.Object.assign.ensure (C:\dev\go\qp\node_modules\@linaria\babel-preset\lib\module.js:214:13)
at C:\dev\go\qp\apps\GroupOnline.QuotationPlatformHost\src\components\quickform-container\goTokens.tsx:4:22
at C:\dev\go\qp\apps\GroupOnline.QuotationPlatformHost\src\components\quickform-container\goTokens.tsx:17:3
at Script.runInContext (node:vm:149:12)
at Module.evaluate (C:\dev\go\qp\node_modules\@linaria\babel-preset\lib\module.js:283:12)
at require.Object.assign.ensure (C:\dev\go\qp\node_modules\@linaria\babel-preset\lib\module.js:214:13)
at C:\dev\go\qp\apps\GroupOnline.QuotationPlatformHost\src\components\quickform\GroupOnlineQuickform.tsx:3:17
at C:\dev\go\qp\apps\GroupOnline.QuotationPlatformHost\src\components\quickform\GroupOnlineQuickform.tsx:40:3
at Script.runInContext (node:vm:149:12)
at Module.evaluate (C:\dev\go\qp\node_modules\@linaria\babel-preset\lib\module.js:283:12)
at evaluate (C:\dev\go\qp\node_modules\@griffel\babel-preset\src\utils\evaluatePathsInVM.js:22:9)
at evaluatePathsInVM (C:\dev\go\qp\node_modules\@griffel\babel-preset\src\utils\evaluatePathsInVM.js:80:21)
at evaluatePaths (C:\dev\go\qp\node_modules\@griffel\babel-preset\src\utils\evaluatePaths.js:22:51)
at PluginPass.exit (C:\dev\go\qp\node_modules\@griffel\babel-preset\src\transformPlugin.js:186:59)
at newFn (C:\dev\go\qp\node_modules\@babel\traverse\lib\visitors.js:172:14)
at NodePath._call (C:\dev\go\qp\node_modules\@babel\traverse\lib\path\context.js:49:20)
at NodePath.call (C:\dev\go\qp\node_modules\@babel\traverse\lib\path\context.js:39:18)
at NodePath.visit (C:\dev\go\qp\node_modules\@babel\traverse\lib\path\context.js:96:8)
at TraversalContext.visitQueue (C:\dev\go\qp\node_modules\@babel\traverse\lib\context.js:90:16)
at TraversalContext.visitSingle (C:\dev\go\qp\node_modules\@babel\traverse\lib\context.js:66:19)
at TraversalContext.visit (C:\dev\go\qp\node_modules\@babel\traverse\lib\context.js:113:19)
at traverseNode (C:\dev\go\qp\node_modules\@babel\traverse\lib\traverse-node.js:22:17)
at traverse (C:\dev\go\qp\node_modules\@babel\traverse\lib\index.js:53:34)
at transformFile (C:\dev\go\qp\node_modules\@babel\core\lib\transformation\index.js:82:31)
at transformFile.next (<anonymous>)
at run (C:\dev\go\qp\node_modules\@babel\core\lib\transformation\index.js:24:12)
at run.next (<anonymous>)
at C:\dev\go\qp\node_modules\@babel\core\lib\transform-ast.js:23:33
at Generator.next (<anonymous>)
at evaluateSync (C:\dev\go\qp\node_modules\gensync\index.js:251:28)
at sync (C:\dev\go\qp\node_modules\gensync\index.js:89:14)
at stopHiding - secret - don't use this - v1 (C:\dev\go\qp\node_modules\@babel\core\lib\errors\rewrite-stack-trace.js:47:12)
at Object.transformFromAstSync (C:\dev\go\qp\node_modules\@babel\core\lib\transform-ast.js:43:83)
at transformSync (C:\dev\go\qp\node_modules\@griffel\webpack-loader\src\transformSync.js:21:35)
at Object.webpackLoader (C:\dev\go\qp\node_modules\@griffel\webpack-loader\src\webpackLoader.js:80:52)
Import trace for requested module:
./src/components/quickform/GroupOnlineQuickform.tsx
> Build failed because of webpack errors
I was able to track down the issue, in the new project we was importing our tokens .
in a component if using tokens from library then the error surfaces, but if we just type out the var(...) manually things work
"use client";
import { QuickForm, QuickFormDefinition, QuickFormProvider, quickformtokens } from "@eavfw/quickform-core"
import { QuotationFormStatus } from "../../eav/quotationFormTemplates.api";
import { makeStaticStyles, makeStyles } from "@fluentui/react-components";
import { goTokens } from "../../style/tokens";
import { useState } from "react";
import { useServerInsertedHTML } from "next/navigation";
const useQuickformStyles = makeStyles({
slide: {
margin: "2rem auto",
maxWidth: "72rem",
},
ending: {
alignItems: "center",
lineHeight: "1.4"
},
slideButton: {
paddingLeft: '25px',
paddingRight: '25px',
borderRadius: quickformtokens.questionBorderRadius // 'var(--slide-button-border-radius,100px)' This works when typed directly, not imported tokens
},
banner: {
padding: '1rem 0',
marginBottom: '4px',
display: 'flex',
justifyContent: 'center',
fontWeight: '900',
borderRadius: '20px',
boxShadow: 'rgba(100, 100, 111, 0.2) 0px 7px 29px 0px',
}
});
Library Tokens
/* Color-scheme is inspired by Material Design (https://m2.material.io/design/color/the-color-system.html#color-theme-creation) */
import { log } from "console";
import { resolveQuickFormService } from "../services/QuickFormServices";
import { camelToKebabCase, defineVariables } from "../utils/quickformUtils";
import { defaultQuickFormTokens } from "./defaultQuickFormTokens";
type Color = string;
type FontSize = string;
type Gap = string;
type NuancedColor<T extends string> = `${T}${'Darker' | 'Lighter'}${'' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900}`;
type QuickFormStructuredColorProperties = 'primary' | 'onPrimary' | 'secondary' | 'onSecondary' | 'background' | 'onBackground' | 'surface' | 'onSurface' | 'error' | 'onError';
type QuickFormTokensBase = {
/* Pure colors */
white: Color,
black: Color,
warning: Color,
success: Color,
info: Color,
questionPlaceholderColor: Color,
/* Structured colors */
primary: Color,
onPrimary: Color,
secondary: Color,
onSecondary: Color,
background: Color,
onBackground: Color,
surface: Color,
onSurface: Color,
error: Color,
onError: Color,
/* Typography */
fontFamily: string,
headlineFontSize: FontSize;
subtitleFontSize: FontSize;
paragraphFontSize: FontSize;
paragraphMobileFontSize: FontSize;
btnFontSize: FontSize,
btnEnterKeyTextFontSize: FontSize,
btnFontWeight: number,
multilineTextFontSize: FontSize,
multilineTextMobileFontSize: FontSize,
questionHeadlineFontSize: FontSize,
questionHeadlineFontWeight: number,
questionParagraphFontSize: FontSize,
questionNumberFontSize: FontSize,
questionInputFontSize: FontSize,
/* Structural properties */
gap1: Gap,
gap2: Gap,
gap4: Gap,
disabledOpacity: number;
dividerOpacity: number;
lowEmphasisOpacity: number;
mediumEmphasisOpacity: number;
highEmphasisOpacity: number;
// Question
questionBorderRadius: string;
questionTopMargin: string;
questionBottomMargin: string;
questionPadding: string;
questionInputGap: Gap,
questionPaddingBottom: string;
slideButtonIconSize: string;
};
export type QuickFormTokens = QuickFormTokensBase & {
[Property in NuancedColor<QuickFormStructuredColorProperties>]?: Color;
};
/**
* Defines and returns the CSS variables for the Quick Form based on provided tokens.
* This function merges user-defined tokens with the default tokens, ensuring that
* any customizations are applied on top of the defaults. The result is a flat object
* where keys are CSS variable names in camel-case, suitable for direct use in styling objects that use React.CSSProperties.
*
* @param tokens - An array of token objects. Each object can partially override the default tokens.
* @returns A flat object with CSS camel-case variable names as keys and their corresponding values.
*/
export const defineQuickFormTokens = (...tokens: Array<Partial<QuickFormTokens>>) => {
const logger = resolveQuickFormService("logger");
logger.log("Merging Quick Form tokens.", tokens);
// Merges and overrides default tokens with provided ones in reverse order for precedence.
const mergedTokens = tokens.reduce((prevTokens, currentTokens) => {
logger.log("Merging currentTokens into prevTokens", prevTokens, currentTokens);
return ({
...prevTokens,
...currentTokens,
})
}, defaultQuickFormTokens);
// Ensures merged tokens are camelCase CSS variables that React.CSSProperties can use and return.
return defineVariables(mergedTokens);
};
/**
* Provides QuickForm with css tokens to be passed around in the components so they refer to the same css variables that are loaded into the QuickFormProvider upon application instantiation.
* @returns A flat object with CSS variables in camelCase that have corresponding values provided as kebab-case tokens variable names that map to globally defined colors.
* See example: quickformtokens = { onPrimary: "var(--on-primary)"; onSecondary: "var(--on-secondary)" } and so on. You get the idea.
*/
export const quickformtokens = camelToKebabCase(defaultQuickFormTokens);
@layershifter - are there any special way one need to export tokens for them to be used. I looked at fluentui and it seems it is just a dictionary of key value - i changed above to the same to not have any logic like the cameltoKebabCase, but the result is the same.
Need to figure out how to export tokens from my lib so it can be used in consumer project with css extraction
(will follow up on Monday 👀 )
@pksorensen do I correctly understand that you have a monorepo:
Are you using Yarn Workspaces? NPM?
Or should @eavfw/quickform-core come from a separate repo? (i.e. external dependency)
Monorepo case
It's odd that it gets resolved into node_modules/*, should be C:\dev\go\qp\packages\SMTH.
External dependency
In this case, it seems that @eavfw/quickform-core it's not bundled properly. Something like tsup (with bundling both ESM & CJS) + proper fields in package.json (i.e. main & module) should solve this case.
@pksorensen Were you able to solve that problem? Mind sharing the solution please?