Skip to content

Commit

Permalink
Task: Use different approach to build react-ui-components: build each…
Browse files Browse the repository at this point in the history
… file separately

the advantage is we dont have so many empty chunks and less files to publish.
Also previously with importing from the unstyled compontents would still include css as the chunking wasnt optimal.
  • Loading branch information
mhsdesign committed Feb 21, 2023
1 parent d8ab716 commit 4636db5
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 99 deletions.
6 changes: 4 additions & 2 deletions cssModules.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ const cssModules = (options) => {
sourceMap: true,
targets: options.targets,
drafts: options.drafts,
visitor: options.visitor
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) {
Expand All @@ -64,7 +66,7 @@ const cssModules = (options) => {

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

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

transpiledCssModulesMap.set(
id,
Expand Down
189 changes: 97 additions & 92 deletions packages/react-ui-components/esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,106 +3,111 @@ const { compileWithCssVariables } = require('../../cssVariables')
const nodePath = require("path")
const { writeFile, mkdir } = require("fs/promises")

const packageJson = require("./package.json");
const { cssModules } = require('../../cssModules');
const { build } = require('esbuild');

build({
entryPoints: [
"./src/index.ts",
"./src/unstyled.ts",
"./src/identifiers.ts",
const { readdirSync } = require("fs")

// we use each component as entry point to not bundle all code directly into the index.js
// so we have proper code splitting when importing only a single component from this lib
"./src/enhanceWithClickOutside",
"./src/Badge",
"./src/Bar",
"./src/Button",
"./src/ButtonGroup",
"./src/CheckBox",
"./src/DateInput",
"./src/Dialog",
"./src/DropDown",
"./src/Frame",
"./src/Headline",
"./src/Icon",
"./src/IconButton",
"./src/IconButtonDropDown",
"./src/Label",
"./src/Logo",
"./src/SelectBox",
"./src/SideBar",
"./src/Tabs",
"./src/TextArea",
"./src/TextInput",
"./src/ToggablePanel",
"./src/Tooltip",
"./src/Tree",
"./src/MultiSelectBox",
"./src/MultiSelectBox_ListPreviewSortable",
"./src/SelectBox_Option_SingleLine",
"./src/SelectBox_Option_MultiLineWithThumbnail"
],
external: Object.keys({...packageJson.dependencies, ...packageJson.peerDependencies}),
outdir: "dist",
sourcemap: "linked",
logLevel: 'info',
target: 'es2020',
assetNames: './_css/[hash]',
chunkNames: './_chunk/[hash]',
color: true,
bundle: true,
splitting: true,
format: "esm",
loader: {
'.js': 'tsx',
'.svg': 'dataurl',
'.css': 'copy'
},
metafile: true,
write: false, // we dont write directly see `.then()` below
plugins: [
cssModules(
{
includeFilter: /\.css$/,
visitor: compileWithCssVariables(),
targets: {
chrome: 80 // aligns somewhat to es2020
},
drafts: {
nesting: true
},
cssModulesPattern: `neos-[hash]_[local]`
}
)
]
}).then((result) => {
if (result.errors.length) {
return;
/**
* @param {String} dir
* @returns {Generator<String>}
*/
function *walkSync(dir) {
const files = readdirSync(dir, { withFileTypes: true });
for (const file of files) {
if (file.isDirectory()) {
yield* walkSync(nodePath.join(dir, file.name));
} else {
yield nodePath.join(dir, file.name);
}
}
}

async function main() {

// check for incorrect build or if we have accidentally bundled dependencies what we dont want at all ;)
for (const path of Object.keys(result.metafile.inputs)) {
if (path.startsWith("src/") || path.startsWith("css-modules:")) {
continue;
/**
* we select all ts,js files that are not tests
* this logic should always align to the include and exclude patterns in `tsconfig.esmtypes.json`
*/
const entryPoints = [...walkSync(nodePath.join(__dirname, "src"))].filter((file) => {
if (/(\.spec\.[^/]+|\.story\.jsx?|\.d\.ts)$/.test(file)) {
return false;
}
throw new Error(`File ${path} doesnt belong to the currently bundled package, yet is not listed as dependeny.`)
}
if (/(\.tsx?|\.jsx?)$/.test(file)) {
return true;
}
return false;
})

// we regex replace unused chunk imports in the js files,
// this fixes the suboptimal output
// see issue https://github.com/evanw/esbuild/issues/2922
console.time("Build")

const unusedImportsRegex = /^import ".*_chunk\/[^;]+;$/gm;
result.outputFiles.forEach(async (file) => {
await mkdir(nodePath.dirname(file.path), { recursive: true})
const buildResultsPromise = entryPoints.map((entryPoint) => build({
entryPoints: [entryPoint],
outbase: "src",
outdir: "dist",
sourcemap: "linked",
bundle: true,
logLevel: 'silent',
target: 'es2020',
assetNames: './_css/[hash]',
color: true,
format: "esm",
write: false,
loader: {
'.js': 'tsx',
'.svg': 'dataurl',
'.css': 'copy'
},
plugins: [
{
name: "bundel-only-ressources-for-each-entry",
setup: ({onResolve}) => {
onResolve({filter: /.*/}, ({path}) => {
if (path.endsWith(".css") || path.endsWith(".svg")) {
return;
}

if (file.path.endsWith(".js") && !file.path.endsWith(".map.js")) {
const replacedUnusedImports = file.text.replace(unusedImportsRegex, "");
writeFile(file.path, replacedUnusedImports, { encoding: "utf8" })
} else {
writeFile(file.path, file.contents)
if (path === entryPoint) {
return;
}

return {
external: true
}
})
}
},
cssModules(
{
includeFilter: /\.css$/,
visitor: compileWithCssVariables(),
targets: {
chrome: 80 // aligns somewhat to es2020
},
drafts: {
nesting: true
},
cssModulesPattern: `neos-[hash]_[local]`
}
)
]
}))

const buildResults = await Promise.all(buildResultsPromise)
const writtenFiles = new Set();
for (const buildResult of buildResults) {
for (const file of buildResult.outputFiles) {
if (writtenFiles.has(file.path)) {
continue;
}
writtenFiles.add(file.path);
await mkdir(nodePath.dirname(file.path), { recursive: true })
writeFile(file.path, file.contents);
}
})
})
}

console.timeEnd("Build")
console.log(`Wrote ${writtenFiles.size} files.`);
}

main();
10 changes: 5 additions & 5 deletions packages/react-ui-components/example/test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { render } from "react-dom";
import { IconButton, Icon, Button, Headline, Label, ToggablePanel } from "../dist/index"
import { IconButton, Icon, Button, Headline, Logo, ToggablePanel } from "../dist/index"

import './font.css'; // The components

Expand All @@ -22,19 +22,19 @@ const App = () => (
gap: "2rem",
width: "100px"
}}>
<Logo />
<Headline type="h1">Hello</Headline>
<Label>Hi</Label>
<ToggablePanel isOpen={true}>
<ToggablePanel>
<ToggablePanel.Header>
Header
</ToggablePanel.Header>
<ToggablePanel.Contents>
Contents
Marc Henry war hier ^^
</ToggablePanel.Contents>
</ToggablePanel>
<IconButton icon="neos" />
<Icon icon="swimming-pool" />
<Button>Hello Welt</Button>
<Button>Hallo Welt</Button>
</div>
)

Expand Down

0 comments on commit 4636db5

Please sign in to comment.