Skip to content

Commit 3ceedb1

Browse files
authored
feat: add build style (#1201)
* fix: eliminate TS6053 error * chore: add deps * feat: add build style * refactor(antd): use build style * refactor(next): use build style * fix: eliminate ts error in rollup-plugin-postcss * feat: add build all styles output option
1 parent 1da31ca commit 3ceedb1

File tree

17 files changed

+349
-80
lines changed

17 files changed

+349
-80
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@
5252
"devDependencies": {
5353
"@alifd/next": "^1.19.1",
5454
"@rollup/plugin-commonjs": "^17.0.0",
55+
"less": "^4.1.1",
56+
"less-plugin-npm-import": "^2.1.0",
57+
"rollup-plugin-postcss": "^4.0.0",
58+
"postcss": "^8.0.0",
5559
"@testing-library/jest-dom": "^5.0.0",
5660
"@testing-library/react": "^11.2.3",
5761
"@testing-library/vue": "^5.6.1",
@@ -183,4 +187,4 @@
183187
"dependencies": {
184188
"@ant-design/icons": "^4.0.2"
185189
}
186-
}
190+
}

packages/antd/build-style.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { build } from '../../scripts/build-style'
2+
3+
build({
4+
esStr: 'antd/es/',
5+
libStr: 'antd/lib/',
6+
styleEntry: 'style.less',
7+
allStylesOutputFile: 'dist/antd.css',
8+
// antd/es/button/style/index ===> antd/es/button/style/css
9+
importCssCompilerToCssTransform: (v) =>
10+
v.replace(/'antd\/(es|lib)\/(.*)'/, (subStr) =>
11+
subStr.replace(/\/style\/index'$/, `/style/css'`)
12+
),
13+
})

packages/antd/copy.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

packages/antd/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
},
2323
"scripts": {
2424
"start": "dumi dev",
25-
"build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm && npm run build:umd && npm run copy:style",
26-
"copy:style": "cross-env INIT_RUN=true ts-node copy",
25+
"build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm && npm run build:style",
26+
"build:style": "ts-node build-style",
2727
"build:cjs": "tsc --declaration",
2828
"build:esm": "tsc --declaration --module es2015 --outDir esm",
2929
"build:umd": "rollup --config",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import './style.less'
1+
import './style.less'

packages/antd/src/form/style.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import './style.less'
1+
import './style.less'

packages/next/build-style.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { build } from '../../scripts/build-style'
2+
3+
build({
4+
esStr: '@alifd/next/es/',
5+
libStr: '@alifd/next/lib/',
6+
styleEntry: 'main.scss',
7+
allStylesOutputFile: 'dist/next.css',
8+
// antd/es/button/style/index ===> antd/es/button/style/css
9+
importCssCompilerToCssTransform: (v) =>
10+
v.replace(/'@alifd\/next\/(es|lib)\/(.*)'/g, (subStr) =>
11+
subStr.replace(/\/style'$/, `/index.css'`)
12+
),
13+
})

packages/next/copy.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/next/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
},
2323
"scripts": {
2424
"start": "dumi dev",
25-
"build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm && npm run build:umd && npm run copy:style",
26-
"copy:style": "cross-env INIT_RUN=true ts-node copy",
25+
"build": "rimraf -rf lib esm dist && npm run build:cjs && npm run build:esm && npm run build:style",
26+
"build:style": "ts-node build-style",
2727
"build:cjs": "tsc --declaration",
2828
"build:esm": "tsc --declaration --module es2015 --outDir esm",
2929
"build:umd": "rollup --config",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import './main.scss'
1+
import './main.scss'

packages/next/src/form/style.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import './main.scss'
1+
import './main.scss'

scripts/build-style/buildAllStyles.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import fs from 'fs-extra'
2+
import { join } from 'path'
3+
import { identifier } from 'safe-identifier'
4+
5+
import typescript from 'rollup-plugin-typescript2'
6+
7+
import { build, getRollupBasePlugin } from './helper'
8+
9+
/**
10+
* @ref https://github.com/egoist/rollup-plugin-postcss/blob/master/src/postcss-loader.js
11+
*/
12+
const styleInjectPath = require
13+
.resolve('style-inject/dist/style-inject.es')
14+
.replace(/[\\/]+/g, '/')
15+
16+
let styleInjectText = ''
17+
const generateCssStyleInject = async (cssFilePath: string) => {
18+
if (!styleInjectText) {
19+
styleInjectText = (await fs.readFile(styleInjectPath)).toString()
20+
styleInjectText = styleInjectText.replace('export default styleInject;', '')
21+
}
22+
23+
let cssContent = (await fs.readFile(cssFilePath)).toString()
24+
25+
// 删除可能存在的 sourceMap 注释
26+
cssContent = cssContent.replace(/\n\/\*#(.*)css.map\s\*\//g, '')
27+
28+
const cssVariableName = identifier('css', true)
29+
30+
return fs.outputFile(
31+
cssFilePath.replace('.css', '.js'),
32+
styleInjectText +
33+
`\nvar ${cssVariableName} = "${cssContent}";\n\nstyleInject(${cssVariableName})`
34+
)
35+
}
36+
37+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
38+
export const buildAllStyles = async (outputFile: string) => {
39+
const outputFilePath = 'dist/formily.css'
40+
41+
await build({
42+
input: 'src/style.ts',
43+
output: {
44+
file: outputFile,
45+
},
46+
plugins: [
47+
typescript({
48+
tsconfig: './tsconfig.json',
49+
tsconfigOverride: {
50+
compilerOptions: {
51+
module: 'ESNext',
52+
declaration: false,
53+
},
54+
},
55+
}),
56+
...getRollupBasePlugin(),
57+
],
58+
})
59+
60+
return generateCssStyleInject(join(process.cwd(), outputFile))
61+
}

scripts/build-style/buildStyle.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { copy, readFile, outputFile, existsSync } from 'fs-extra'
2+
3+
import { getRollupBasePlugin, build } from './helper'
4+
5+
export type BuildStyleOptions = {
6+
filename: string
7+
styleEntry: string
8+
importCssCompilerToCssTransform?: (fileContent: string) => string
9+
}
10+
11+
const importCssCompilerToCss = async ({
12+
fileName,
13+
outputFileName,
14+
styleEntry,
15+
transform,
16+
}: {
17+
outputFileName: string
18+
fileName: string
19+
styleEntry: string
20+
transform?: BuildStyleOptions['importCssCompilerToCssTransform']
21+
}) => {
22+
let styleFileContent = (await readFile(fileName)).toString()
23+
24+
if (!styleFileContent) {
25+
return
26+
}
27+
28+
styleFileContent = styleFileContent.replace(
29+
new RegExp(`\.\/${styleEntry}`),
30+
'./css.css'
31+
)
32+
33+
return outputFile(
34+
outputFileName,
35+
transform?.(styleFileContent) || styleFileContent
36+
)
37+
}
38+
39+
const getPaths = (filename: string, moduleType: 'esm' | 'lib') => {
40+
const styleFilePath = filename
41+
.replace(/src\//, `${moduleType}/`)
42+
.replace(/\.ts$/, '.js')
43+
const cssFilePath = styleFilePath.replace(/\/\w+\.js$/, '/css.css')
44+
const cssSourceMapFilePath = `${cssFilePath}.map`
45+
46+
return {
47+
// esm/array-base/style.js
48+
styleFilePath,
49+
// esm/array-base/css.css
50+
cssFilePath,
51+
// esm/array-base/css.css.map
52+
cssSourceMapFilePath,
53+
}
54+
}
55+
56+
const buildCss = async ({
57+
filename,
58+
esmPaths,
59+
libPaths,
60+
styleEntry,
61+
}: Pick<BuildStyleOptions, 'filename' | 'styleEntry'> &
62+
Record<'esmPaths' | 'libPaths', ReturnType<typeof getPaths>>) => {
63+
// src/array-base/style.ts ===> src/array-base/style.less
64+
const input = filename.replace(/style\.ts$/, styleEntry)
65+
66+
if (!existsSync(input)) {
67+
return
68+
}
69+
70+
await build({
71+
input,
72+
output: {
73+
file: esmPaths.cssFilePath,
74+
},
75+
plugins: getRollupBasePlugin(),
76+
})
77+
78+
return Promise.all([
79+
copy(esmPaths.cssFilePath, libPaths.cssFilePath),
80+
existsSync(esmPaths.cssSourceMapFilePath) &&
81+
copy(esmPaths.cssSourceMapFilePath, libPaths.cssSourceMapFilePath),
82+
])
83+
}
84+
85+
export const buildStyle = async ({
86+
// xxxx/style.ts
87+
filename,
88+
// example: style.less/main.scss
89+
styleEntry,
90+
importCssCompilerToCssTransform,
91+
}: BuildStyleOptions): Promise<unknown> => {
92+
const esmPaths = getPaths(filename, 'esm')
93+
const libPaths = getPaths(filename, 'lib')
94+
95+
await buildCss({
96+
filename,
97+
esmPaths,
98+
libPaths,
99+
styleEntry,
100+
})
101+
102+
return Promise.all([
103+
importCssCompilerToCss({
104+
fileName: esmPaths.styleFilePath,
105+
outputFileName: esmPaths.cssFilePath.replace(/\.css$/, '.js'),
106+
styleEntry,
107+
transform: importCssCompilerToCssTransform,
108+
}),
109+
importCssCompilerToCss({
110+
fileName: libPaths.styleFilePath,
111+
outputFileName: libPaths.cssFilePath.replace(/\.css$/, '.js'),
112+
styleEntry,
113+
transform: importCssCompilerToCssTransform,
114+
}),
115+
])
116+
}

scripts/build-style/copy.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2+
import { copy, readFile, writeFile, existsSync } from 'fs-extra'
3+
import glob from 'glob'
4+
5+
export type CopyBaseOptions = Record<'esStr' | 'libStr', string>
6+
7+
const importLibToEs = async ({
8+
libStr,
9+
esStr,
10+
filename,
11+
}: CopyBaseOptions & { filename: string }) => {
12+
if (!existsSync(filename)) {
13+
return Promise.resolve()
14+
}
15+
16+
const fileContent: string = (await readFile(filename)).toString()
17+
18+
return writeFile(
19+
filename,
20+
fileContent.replace(new RegExp(libStr, 'g'), esStr)
21+
)
22+
}
23+
24+
export const runCopy = ({
25+
resolveForItem,
26+
...lastOpts
27+
}: CopyBaseOptions & { resolveForItem?: (filename: string) => unknown }) => {
28+
return new Promise((resolve, reject) => {
29+
glob(`./src/**/*`, (err, files) => {
30+
if (err) {
31+
return reject(err)
32+
}
33+
34+
const all = [] as Promise<unknown>[]
35+
36+
for (let i = 0; i < files.length; i += 1) {
37+
const filename = files[i]
38+
39+
resolveForItem?.(filename)
40+
41+
if (/\.(less|scss)$/.test(filename)) {
42+
all.push(copy(filename, filename.replace(/src\//, 'esm/')))
43+
all.push(copy(filename, filename.replace(/src\//, 'lib/')))
44+
45+
continue
46+
}
47+
48+
if (/\/style.ts$/.test(filename)) {
49+
importLibToEs({
50+
...lastOpts,
51+
filename: filename.replace(/src\//, 'esm/').replace(/\.ts$/, '.js'),
52+
})
53+
54+
continue
55+
}
56+
}
57+
})
58+
})
59+
}

0 commit comments

Comments
 (0)