Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: CSS build refactor (make react-ui-components easy to use) #3366

Merged
merged 50 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5694006
TASK: Rename scss files to css
mhsdesign Feb 11, 2023
36dfbdc
Task: Replace @extends with composes: reset from "../reset.css";
mhsdesign Feb 11, 2023
b9acf92
Task: Rewrite reset.scss in css
mhsdesign Feb 11, 2023
788608c
Task: Update esbuild to remove duplicate css across files
mhsdesign Feb 11, 2023
d46b909
Task: Remove sass
mhsdesign Feb 11, 2023
f2e1a85
Task: Apply `&` in nested css to comply with the draft
mhsdesign Feb 12, 2023
d19234b
Task: Use css module composes for grid-area
mhsdesign Feb 12, 2023
e59b797
Task: Css modules use `:global(` function syntax instead of context s…
mhsdesign Feb 14, 2023
51e03a1
Task: Use lightningcss for css modules instead of postcss
mhsdesign Feb 14, 2023
426f0a8
Feature: Fully working "react-ui-components" consumer friendly build
mhsdesign Feb 14, 2023
bc54470
Task: revert to not use :where() in .reset
mhsdesign Feb 14, 2023
e322532
Task: rename reset.css to reset.module.css
mhsdesign Feb 14, 2023
67bf977
Task: mark old css var config as LEGACY
mhsdesign Feb 14, 2023
ca5ce09
Task: document things
mhsdesign Feb 14, 2023
b368fbb
Task: Fix css variables lightningcss plugin
mhsdesign Feb 15, 2023
80f3e34
Task: Fix linter
mhsdesign Feb 15, 2023
5918a72
Task: inline isNil to avoid having '@neos-project/utils-helpers' as n…
mhsdesign Feb 15, 2023
08b6edb
Task: inline @mhsdesign/esbuild-composes-from-css-modules instead
mhsdesign Feb 15, 2023
aa9f549
Task: optimize css modules plugin
mhsdesign Feb 15, 2023
8a401cc
Task: fix linter
mhsdesign Feb 15, 2023
0ede0fb
Task: remove `{isManifestLoaded, getManifest} from '@neos-project/bui…
mhsdesign Feb 15, 2023
837fd53
Task: remove left over references to `.scss`
mhsdesign Feb 15, 2023
4a34d62
Task: remove useless NEOS_BUILD_ROOT
mhsdesign Feb 15, 2023
76a144e
Task: cleanup webpack extensibility and remove its postcss-css-variab…
mhsdesign Feb 15, 2023
57bad12
Task: update esbuild
mhsdesign Feb 15, 2023
86b38c2
Task: remove legacy generation of postcss.rc
mhsdesign Feb 15, 2023
b7202e9
Task: fix linting
mhsdesign Feb 15, 2023
d5cabab
Task: react-ui-components build add check for missing dependencies
mhsdesign Feb 15, 2023
b39b6e4
Task: Fix dateInput style
mhsdesign Feb 17, 2023
c6c9761
Task: cleanup compileWithCssVariables
mhsdesign Feb 17, 2023
48d78fe
Merge remote-tracking branch 'origin/8.3' into feature/cssBuildRefactor
mhsdesign Feb 17, 2023
5850c1a
TASK: Analyze bundle size and health `node esbuild.js --production --…
mhsdesign Feb 18, 2023
f089c83
TasK: Make neos-ui/packages 100% pure esm
mhsdesign Feb 18, 2023
3687084
Bugfix: Revert css style changes #3330 and #3282
mhsdesign Feb 19, 2023
f435ee2
TASK: explain `value == null`
mhsdesign Feb 19, 2023
d7f736d
TASK: Rect-ui-components only expose `index` and `unstyled`
mhsdesign Feb 19, 2023
328c107
Bugfix: Remove sideeffect from `<Icon />` #3378
mhsdesign Feb 19, 2023
79dcd4b
Task: Prefix dist cssmodule from react-ui-components to prevent namin…
mhsdesign Feb 19, 2023
ac52aa4
Task: Fix CI Install
mhsdesign Feb 19, 2023
f326188
Task: React-ui-components build faster build consistency check
mhsdesign Feb 19, 2023
977dee4
Task: Fix Font-awesome tests
mhsdesign Feb 19, 2023
1059be2
TASK: Document new usage ;)
mhsdesign Feb 20, 2023
f67ce2d
Merge remote-tracking branch 'origin/8.3' into feature/cssBuildRefactor
mhsdesign Feb 20, 2023
2128f07
Task: Cleanup react-ui-component typescript-utils
mhsdesign Feb 20, 2023
fd993bd
Task: Better splitting & Docs
mhsdesign Feb 20, 2023
8087038
Update README.md
mhsdesign Feb 21, 2023
d8ab716
Docs: Add example and how to use Noto Sans font
mhsdesign Feb 21, 2023
eefb66d
Task: Use different approach to build react-ui-components: build each…
mhsdesign Feb 21, 2023
a74638e
Task: cssModules omit sourcemap for generated code
mhsdesign Feb 22, 2023
f710274
Merge pull request #3383 from neos/task/analyzeBundleSizeAndHealth
markusguenther Feb 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ lcov.info
#
Build/Selenium/Settings.yaml

#
# Custom livereload settings
#
.webpack.livereload.local.js

#
# Application & development dependencies.
#
Expand All @@ -29,6 +24,7 @@ packages/*/yarn.lock
#
Resources/Public/Build/*
!Resources/Public/Build/.gitkeep
*.tsbuildinfo

#
# editors / IDEs
Expand All @@ -47,4 +43,3 @@ Resources/Public/Build/*
!.yarn/releases
!.yarn/sdks
!.yarn/versions
tsconfig.tsbuildinfo
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
28 changes: 6 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,42 +75,26 @@ setup: check-requirements install build ## Run a clean setup
# Builds
################################################################################


# TODO: figure out how to pass a parameter to other targets to reduce redundancy
# Builds the subpackages for standalone use.
build-subpackages:
yarn workspaces foreach --parallel --topological-dev run build
make build-react-ui-components-standalone

# we build the react UI components ready for standalone usage;
# so that they can be published on NPM properly.

## Build the react UI components ready for standalone usage.
build-react-ui-components-standalone:
yarn workspace @neos-project/react-ui-components build-standalone-esm
yarn workspaces foreach --parallel run build

## Runs the development build.
build:
NEOS_BUILD_ROOT=$(shell pwd) node esbuild.js
node esbuild.js

## Watches the source files for changes and runs a build in case.
build-watch:
NEOS_BUILD_ROOT=$(shell pwd) node esbuild.js --watch

## Watches (and polls) the source files on a file share.
build-watch-poll:
echo "not implemented in esbuild, yet! PR Welcome!"
node esbuild.js --watch

# clean anything before building for production just to be sure
## Runs the production build. And also builds the subpackages for standalone use.
build-production:
$(cross-env) NODE_ENV=production NEOS_BUILD_ROOT=$(shell pwd) \
node esbuild.js
$(cross-env) NODE_ENV=production node esbuild.js
make build-subpackages

build-e2e-testing:
$(cross-env) NODE_ENV=production NEOS_BUILD_ROOT=$(shell pwd) \
node esbuild.js --e2e-testing
$(cross-env) NODE_ENV=production node esbuild.js --e2e-testing

################################################################################
# Code Quality
Expand Down Expand Up @@ -189,7 +173,7 @@ publish-npm: called-with-version

## Cleans dependency folders
clean:
rm -Rf node_modules; rm -rf packages/*/node_modules
rm -rf node_modules; rm -rf packages/*/node_modules


################################################################################
Expand Down
142 changes: 142 additions & 0 deletions cssModules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const { transform } = require('lightningcss');
const { createHash } = require('crypto');
const fs = require("fs/promises");
const { dirname, join } = require("path");

/**
* A generic cssModules plugin for esbuild based on lightningcss
*
* @param {Object} options
* @param {RegExp} options.includeFilter
* @param {RegExp} options.excludeFilter
* @param {import("lightningcss").TransformOptions["visitor"]} options.visitor
* @param {import("lightningcss").TransformOptions["targets"]} options.targets
* @param {import("lightningcss").TransformOptions["drafts"]} options.drafts
* @param {import("lightningcss").CSSModulesConfig["pattern"]} options.cssModulesPattern
* @return {import("esbuild").Plugin}
*/
const cssModules = (options) => {
return {
name: "css-modules",
setup: ({onLoad, onResolve, initialOptions}) => {
const transpiledCssModulesMap = new Map()

onResolve({filter: /^css-modules:\/\//}, ({path}) => {
return {
namespace: "css-modules",
path,
}
})

onLoad({filter: /.*/, namespace: "css-modules"}, ({path}) => {
const {code, resolveDir} = transpiledCssModulesMap.get(path)
return {
contents: code,
loader: initialOptions.loader?.[".css"] ?? "css",
resolveDir,

}
})

onLoad({filter: options.includeFilter ?? /\.module\.css$/}, async ({path}) => {
if (options.excludeFilter && options.excludeFilter.test(path)) {
return;
}

const rawCssBuffer = await fs.readFile(path)

const { code, map, exports } = transform({
filename: path,
code: rawCssBuffer,
analyzeDependencies: false,
cssModules: {
pattern: options.cssModulesPattern ?? `[hash]_[local]`
},
sourceMap: true,
targets: options.targets,
drafts: options.drafts,
visitor: options.visitor,
// this way the correct relative path for the source map will be generated ;)
projectRoot: join(initialOptions.absWorkingDir || process.cwd(), initialOptions.outdir)
});

if (!exports) {
return;
}

const id = "css-modules:\/\/" + createHash("sha256").update(path).digest('base64url') + '.css'

const finalcode = code.toString("utf8") + `/*# sourceMappingURL=data:application/json;base64,${map.toString("base64")} */`;

transpiledCssModulesMap.set(
id,
{ code: finalcode, resolveDir: dirname(path) }
)

const quote = JSON.stringify;

const escape = (string) => JSON.stringify(string).slice(1, -1)

let contents = "";

/** @type {Map<string, string>} */
const dependencies = new Map()

/** @param {String} path */
const importDependeny = (path) => {
if (dependencies.has(path)) {
return dependencies.get(path)
}
const dependenciesName = `dependency_${dependencies.size}`
// prepend dependeny to to the contents
contents = `import ${dependenciesName} from ${quote(path)}\n` + contents;
dependencies.set(path, dependenciesName)
return dependenciesName;
}

contents += `import ${quote(id)}\n`;
contents += `export default {`;

for (const [cssClassReadableName, cssClassExport] of Object.entries(exports)) {

let compiledCssClasses = `"${escape(cssClassExport.name)}`

if (cssClassExport.composes) {
for (const composition of cssClassExport.composes) {
switch (composition.type) {
case "local":
compiledCssClasses += " " + escape(composition.name)
break;

case "global":
compiledCssClasses += " " + escape(composition.name)
break;

case "dependency":
compiledCssClasses += ` " + ${importDependeny(composition.specifier)}[${quote(composition.name)}] + "`
break;
}
}
}

compiledCssClasses += `"`

contents += `${quote(cssClassReadableName)}:${compiledCssClasses},`
}

contents += "}"

// https://github.com/evanw/esbuild/issues/2943#issuecomment-1439755408
const emptyishSourceMap = "data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==";
contents += `\n//# sourceMappingURL=${emptyishSourceMap}`

return {
contents,
loader: "js",
}
})
}
}
}

module.exports = { cssModules }
63 changes: 63 additions & 0 deletions cssVariables.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/** Global CSS variables for Neos.Ui */

/** they are compiled into the source code via our buildstack */
:root {
--spacing-GoldenUnit: 40px;
--spacing-Full: 16px;
--spacing-Half: 8px;
--spacing-Quarter: 4px;
--size-SidebarWidth: 320px;
--transition-Fast: .1s;
--transition-Default: .25s;
--transition-Slow: .5s;
--zIndex-SecondaryToolbar-LinkIconButtonFlyout: 1;
--zIndex-FlashMessageContainer: 60;
--zIndex-LoadingIndicatorContainer: 50;
--zIndex-SecondaryInspector-Context: 1;
--zIndex-SecondaryInspector-Iframe: 2;
--zIndex-SecondaryInspector-Close: 3;
--zIndex-SecondaryInspectorElevated-Context: 1;
--zIndex-SecondaryInspectorElevated-DropdownContents: 2;
--zIndex-Dialog-Context: 1;
--zIndex-FullScreenClose-Context: 1;
--zIndex-Drawer: 45;
--zIndex-Bar-Context: 1;
--zIndex-PrimaryToolbar: 40;
--zIndex-CheckboxInput-Context: 1;
--zIndex-DropdownContents-Context: 1;
--zIndex-SelectBoxContents: 40;
--zIndex-NotInlineEditableOverlay-Context: 1;
--zIndex-CalendarFakeInputMirror-Context: 1;
--zIndex-RdtPicker-Context: 1;
--zIndex-SideBar-DropTargetBefore: 1;
--zIndex-SideBar-DropTargetAfter: 2;
--zIndex-WrapperDropdown-Context: 1;
--zIndex-UnappliedChangesOverlay-Context: 1;
--zIndex-NodeToolBar: 2147483646;
--fontSize-Base: 14px;
--fontSize-Small: 12px;
--fontsHeadings-Family: "Noto Sans";
--fontsHeadings-Style: "Regular";
--fontsHeadings-CssWeight: 400;
--fontsCopy-Family: "Noto Sans";
--fontsCopy-Style: "Regular";
--fontsCopy-CssWeight: 400;
--colors-PrimaryViolet: #26224C;
--colors-PrimaryVioletHover: #342f5f;
--colors-PrimaryBlue: #00ADEE;
--colors-PrimaryBlueHover: #35c3f8;
--colors-ContrastDarkest: #141414;
--colors-ContrastDarker: #222;
--colors-ContrastDark: #3f3f3f;
--colors-ContrastNeutral: #323232;
--colors-ContrastBright: #999;
--colors-ContrastBrighter: #adadad;
--colors-ContrastBrightest: #FFF;
--colors-Success: #00a338;
--colors-SuccessHover: #0bb344;
--colors-Warn: #ff8700;
--colors-WarnHover: #fda23d;
--colors-Error: #ff460d;
--colors-ErrorHover: #ff6a3c;
--colors-UncheckedCheckboxTick: #5B5B5B;
}
49 changes: 49 additions & 0 deletions cssVariables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { transform } = require('lightningcss');
const { readFileSync } = require("fs");
const { join } = require("path")

/** @type {Record<string, import('lightningcss').TokenOrValue[]>} */
const cssVariables = {}

// we extract all custom variable declarations so we can use the css syntax
// to declare the variables and dont need to write them in lightningcss AST ourselves
transform({
code: readFileSync(join(__dirname, "cssVariables.css")),
visitor: {
Declaration: ({property, value}) => {
if (property !== "custom") {
throw new Error("Only variable declarations expected.")
}
cssVariables[value.name] = value.value
}
}
})

/**
* lightningcss AST visitor (plugin), to compile the used CSS variables directly into the css
*
* @returns {import("lightningcss").Visitor}
*/
const compileWithCssVariables = () => ({
Variable: (variable) => {
const variableValueTokens = cssVariables[variable.name.ident];
return [
...variableValueTokens,
{
// we a append a single space to the tokenList so that when the value is insertet
// it wont collide with further parameters like in this case:
// padding: 0 var(--spacing-GoldenUnit) 0 var(--spacing-Full);
// otherwise we would get:
// padding: 0 40px0 16px
// |__________ here must be a space
type: "token",
value: {
type: "delim",
value: " "
}
}
]
}
})

module.exports = { compileWithCssVariables }
Loading