@next-core/build-next-bricks 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,30 +4,44 @@ import { existsSync } from "node:fs";
4
4
  import build from "../src/build.js";
5
5
  import scanBricks from "../src/scanBricks.js";
6
6
 
7
+ /**
8
+ * @typedef {T | Array<T>} MaybeArray<T>
9
+ * @template {string} T
10
+ */
11
+
12
+ /** @typedef {import("@next-core/build-next-bricks").BuildNextBricksConfig} BuildNextBricksConfig */
13
+
7
14
  try {
8
15
  const startTime = Date.now();
9
16
 
10
17
  const packageDir = process.cwd();
11
18
  const configJs = path.join(packageDir, "build.config.js");
12
- /** @type {import("@next-core/build-next-bricks").BuildNextBricksConfig} */
13
- let config = {};
19
+ /** @type {MaybeArray<BuildNextBricksConfig>} */
20
+ let rawConfig = {};
14
21
  if (existsSync(configJs)) {
15
- config = (await import(configJs)).default;
22
+ rawConfig = (await import(configJs)).default;
16
23
  }
17
24
 
18
- if (!config.type || config.type === "bricks") {
19
- const scanBricksStartAt = performance.now();
20
- Object.assign(config, await scanBricks(packageDir));
21
- const scanBricksCost = Math.round(performance.now() - scanBricksStartAt);
22
- console.log(
23
- "Scan bricks done in",
24
- scanBricksCost < 1000
25
- ? `${scanBricksCost}ms`
26
- : `${(scanBricksCost / 1000).toFixed(2)}s`
27
- );
25
+ /** @type {Array<BuildNextBricksConfig>} */
26
+ const configList = [].concat(rawConfig);
27
+
28
+ for (const config of configList) {
29
+ if (!config.type || config.type === "bricks") {
30
+ const scanBricksStartAt = performance.now();
31
+ Object.assign(config, await scanBricks(packageDir));
32
+ const scanBricksCost = Math.round(performance.now() - scanBricksStartAt);
33
+ console.log(
34
+ "Scan bricks done in",
35
+ scanBricksCost < 1000
36
+ ? `${scanBricksCost}ms`
37
+ : `${(scanBricksCost / 1000).toFixed(2)}s`
38
+ );
39
+ }
28
40
  }
29
41
 
30
- const compiler = await build(config);
42
+ const compiler = await build(
43
+ configList.length === 1 ? configList[0] : configList
44
+ );
31
45
 
32
46
  const watch = process.argv.includes("--watch");
33
47
 
package/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import type { Compiler, Configuration, RuleSetRule, container } from "webpack";
2
2
 
3
3
  export declare function build(config: BuildNextBricksConfig): Compiler;
4
+ export declare function getSvgrLoaders(options: {
5
+ /** Set it to true for font icons */
6
+ convertCurrentColor?: boolean;
7
+ }): RuleSetRule["use"];
4
8
 
5
9
  // Types of `SharedConfig` and `SharedObject` are copied from webpack.
6
10
 
@@ -65,13 +69,20 @@ export interface BuildNextBricksConfig {
65
69
  type?: "bricks" | "container" | "brick-playground";
66
70
  mode?: "development" | "production";
67
71
  entry?: Record<string, string>;
72
+ /** Defaults to "dist" */
73
+ outputPath?: string;
74
+ devOnlyOutputPublicPath?: string;
68
75
  extractCss?: boolean;
69
- svgAsAsset?: boolean;
76
+ /** Treat svg as React component instead of asset */
77
+ svgAsReactComponent?: boolean;
78
+ /** Customize rules for svg */
79
+ svgRules?: RuleSetRule[];
80
+ /** By default the image assets are named `images/[hash][ext][query]` */
70
81
  imageAssetFilename?: string | ((pathData: any, assetInfo: any) => string);
71
82
  plugins?: Configuration["plugins"];
72
83
  moduleRules?: RuleSetRule[];
73
84
  exposes?: ConstructorParameters<typeof container.ModuleFederationPlugin>;
74
85
  dependencies?: Record<string, string[]>;
75
86
  optimization?: Configuration["optimization"];
76
- moduleFederationShared?: SharedObject;
87
+ moduleFederationShared?: SharedObject | false;
77
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next-core/build-next-bricks",
3
- "version": "1.1.2",
3
+ "version": "1.3.0",
4
4
  "description": "Build next bricks",
5
5
  "homepage": "https://github.com/easyops-cn/next-core/tree/master/packages/build-next-bricks",
6
6
  "license": "GPL-3.0",
@@ -46,5 +46,5 @@
46
46
  "typescript": "^5.0.2",
47
47
  "webpack": "^5.76.2"
48
48
  },
49
- "gitHead": "3e4c6996c85fb0bb14330cd1d128dd8ff690bf5e"
49
+ "gitHead": "4db0aebfc3d7991690c736adf7182f327adca534"
50
50
  }
package/src/build.js CHANGED
@@ -8,6 +8,14 @@ import cssnano from "cssnano";
8
8
  import cssnanoPresetLite from "cssnano-preset-lite";
9
9
  import EmitBricksJsonPlugin from "./EmitBricksJsonPlugin.js";
10
10
  import getCamelPackageName from "./getCamelPackageName.js";
11
+ import getSvgrLoaders from "./getSvgrLoaders.js";
12
+
13
+ /**
14
+ * @typedef {T | Array<T>} MaybeArray<T>
15
+ * @template {string} T
16
+ */
17
+
18
+ /** @typedef {import("@next-core/build-next-bricks").BuildNextBricksConfig} BuildNextBricksConfig */
11
19
 
12
20
  const require = createRequire(import.meta.url);
13
21
 
@@ -47,9 +55,10 @@ const getCssLoaders = (cssOptions) => [
47
55
  ];
48
56
 
49
57
  /**
50
- * @param {import("@next-core/build-next-bricks").BuildNextBricksConfig} config
58
+ * @param {BuildNextBricksConfig} config
59
+ * @returns {import("webpack").Configuration}
51
60
  */
52
- export default async function build(config) {
61
+ async function getWebpackConfig(config) {
53
62
  const packageDir = process.cwd();
54
63
  // const isContainer = config.type === "container";
55
64
  const isBricks = !config.type || config.type === "bricks";
@@ -95,49 +104,55 @@ export default async function build(config) {
95
104
  ...sharedSingletonPackages,
96
105
  ];
97
106
 
98
- /** @type {import("@next-core/build-next-bricks").BuildNextBricksConfig["moduleFederationShared"]} */
99
- const shared = Object.fromEntries(
100
- (
101
- await Promise.all(
102
- sharedPackages.map(async (dep) => {
103
- /** @type {string} */
104
- let depPackageJsonPath;
105
- const depPkgName = dep
106
- .split("/")
107
- .slice(0, dep.startsWith("@") ? 2 : 1)
108
- .join("/");
109
- try {
110
- depPackageJsonPath = require.resolve(`${depPkgName}/package.json`, {
111
- paths: [packageDir],
112
- });
113
- } catch (e) {
114
- console.error(`Shared package not found: "${dep}"`);
115
- return;
116
- }
117
- const depPackageJsonFile = await readFile(depPackageJsonPath, {
118
- encoding: "utf-8",
119
- });
120
- const depPackageJson = JSON.parse(depPackageJsonFile);
121
- const customized = config.moduleFederationShared?.[dep];
122
- if (typeof customized === "string") {
123
- return;
124
- }
125
- return [
126
- dep,
127
- {
128
- singleton: sharedSingletonPackages.includes(dep),
129
- version: depPackageJson.version,
130
- requiredVersion:
131
- packageJson.peerDependencies?.[depPkgName] ??
132
- packageJson.devDependencies?.[depPkgName] ??
133
- packageJson.dependencies?.[depPkgName],
134
- ...customized,
135
- },
136
- ];
137
- })
138
- )
139
- ).filter(Boolean)
140
- );
107
+ /** @type {BuildNextBricksConfig["moduleFederationShared"]} */
108
+ const shared =
109
+ config.moduleFederationShared === false
110
+ ? undefined
111
+ : Object.fromEntries(
112
+ (
113
+ await Promise.all(
114
+ sharedPackages.map(async (dep) => {
115
+ /** @type {string} */
116
+ let depPackageJsonPath;
117
+ const depPkgName = dep
118
+ .split("/")
119
+ .slice(0, dep.startsWith("@") ? 2 : 1)
120
+ .join("/");
121
+ try {
122
+ depPackageJsonPath = require.resolve(
123
+ `${depPkgName}/package.json`,
124
+ {
125
+ paths: [packageDir],
126
+ }
127
+ );
128
+ } catch (e) {
129
+ console.error(`Shared package not found: "${dep}"`);
130
+ return;
131
+ }
132
+ const depPackageJsonFile = await readFile(depPackageJsonPath, {
133
+ encoding: "utf-8",
134
+ });
135
+ const depPackageJson = JSON.parse(depPackageJsonFile);
136
+ const customized = config.moduleFederationShared?.[dep];
137
+ if (typeof customized === "string") {
138
+ return;
139
+ }
140
+ return [
141
+ dep,
142
+ {
143
+ singleton: sharedSingletonPackages.includes(dep),
144
+ version: depPackageJson.version,
145
+ requiredVersion:
146
+ packageJson.peerDependencies?.[depPkgName] ??
147
+ packageJson.devDependencies?.[depPkgName] ??
148
+ packageJson.dependencies?.[depPkgName],
149
+ ...customized,
150
+ },
151
+ ];
152
+ })
153
+ )
154
+ ).filter(Boolean)
155
+ );
141
156
 
142
157
  // console.log(packageName, "shared:", shared);
143
158
 
@@ -168,27 +183,24 @@ export default async function build(config) {
168
183
  // };
169
184
  // }
170
185
 
171
- const outputPath = path.join(packageDir, "dist");
186
+ const outputPath = path.join(packageDir, config.outputPath ?? "dist");
172
187
  const chunksDir = isBricks ? "chunks/" : "";
173
188
 
174
- return webpack({
189
+ return {
175
190
  entry: config.entry || {
176
191
  main: "./src/index",
177
192
  },
178
193
  mode,
179
- devServer: {
180
- static: {
181
- directory: outputPath,
182
- },
183
- port: 3001,
184
- },
185
194
  output: {
186
195
  path: outputPath,
187
196
  filename: `${chunksDir}[name].${
188
197
  mode === "development" ? "bundle" : "[contenthash]"
189
198
  }.js`,
190
199
  // filename: "[name].bundle.js",
191
- publicPath: "auto",
200
+ publicPath:
201
+ mode === "development"
202
+ ? config.devOnlyOutputPublicPath ?? "auto"
203
+ : "auto",
192
204
  hashDigestLength: 8,
193
205
  chunkFilename: `${chunksDir}[name]${
194
206
  mode === "development" ? "" : ".[contenthash]"
@@ -240,54 +252,32 @@ export default async function build(config) {
240
252
  rootMode: "upward",
241
253
  },
242
254
  },
243
- config.svgAsAsset
244
- ? {
245
- // Images
246
- test: /\.(png|svg|jpg|jpeg|gif)$/i,
247
- type: "asset/resource",
248
- generator: {
249
- filename:
250
- config.imageAssetFilename ?? "images/[hash][ext][query]",
251
- },
252
- }
253
- : {
254
- test: /\.svg$/i,
255
- issuer(input) {
256
- // The issuer is null (or an empty string) for dynamic import
257
- return !input || /\.[jt]sx?$/.test(input);
258
- },
259
- use: [
260
- {
261
- loader: "babel-loader",
262
- options: {
263
- rootMode: "upward",
264
- },
265
- },
255
+ {
256
+ // Images
257
+ test: new RegExp(
258
+ `\\.(?:${[
259
+ "png",
260
+ "jpg",
261
+ "jpeg",
262
+ "gif",
263
+ ...(config.svgRules ? [] : ["svg"]),
264
+ ].join("|")})$`,
265
+ "i"
266
+ ),
267
+ type: "asset/resource",
268
+ generator: {
269
+ filename: config.imageAssetFilename ?? "images/[hash][ext][query]",
270
+ },
271
+ },
272
+ ...(config.svgRules ??
273
+ (config.svgAsReactComponent
274
+ ? [
266
275
  {
267
- loader: "@svgr/webpack",
268
- options: {
269
- babel: false,
270
- icon: true,
271
- svgoConfig: {
272
- plugins: [
273
- {
274
- name: "preset-default",
275
- params: {
276
- overrides: {
277
- // Keep `viewbox`
278
- removeViewBox: false,
279
- convertColors: {
280
- currentColor: true,
281
- },
282
- },
283
- },
284
- },
285
- ],
286
- },
287
- },
276
+ test: /\.svg$/i,
277
+ use: getSvgrLoaders(false),
288
278
  },
289
- ],
290
- },
279
+ ]
280
+ : [])),
291
281
  {
292
282
  // Fonts
293
283
  test: /\.(woff|woff2|eot|ttf|otf)$/i,
@@ -296,12 +286,12 @@ export default async function build(config) {
296
286
  filename: "fonts/[hash][ext][query]",
297
287
  },
298
288
  },
299
- ...(config.moduleRules || []),
289
+ ...(config.moduleRules ?? []),
300
290
  ],
301
291
  },
302
292
  devtool: false,
303
293
  optimization:
304
- config.optimization ||
294
+ config.optimization ??
305
295
  (isBricks
306
296
  ? {
307
297
  splitChunks: {
@@ -334,26 +324,30 @@ export default async function build(config) {
334
324
  ],
335
325
  }),
336
326
 
337
- new ModuleFederationPlugin({
338
- name: libName,
339
- shared: {
340
- ...config.moduleFederationShared,
341
- ...shared,
342
- },
343
- ...(isBricks
344
- ? {
345
- library: { type: "window", name: libName },
346
- filename:
347
- mode === "development"
348
- ? "index.bundle.js"
349
- : "index.[contenthash].js",
350
- exposes: {
351
- ...config.exposes,
352
- ...extraExposes,
327
+ ...(config.moduleFederationShared !== false
328
+ ? [
329
+ new ModuleFederationPlugin({
330
+ name: libName,
331
+ shared: {
332
+ ...config.moduleFederationShared,
333
+ ...shared,
353
334
  },
354
- }
355
- : null),
356
- }),
335
+ ...(isBricks
336
+ ? {
337
+ library: { type: "window", name: libName },
338
+ filename:
339
+ mode === "development"
340
+ ? "index.bundle.js"
341
+ : "index.[contenthash].js",
342
+ exposes: {
343
+ ...config.exposes,
344
+ ...extraExposes,
345
+ },
346
+ }
347
+ : null),
348
+ }),
349
+ ]
350
+ : []),
357
351
 
358
352
  ...(config.extractCss
359
353
  ? [
@@ -391,5 +385,20 @@ export default async function build(config) {
391
385
 
392
386
  ...(config.plugins || []),
393
387
  ],
394
- });
388
+ };
395
389
  }
390
+
391
+ /**
392
+ * @type {{
393
+ * (config: BuildNextBricksConfig): import("webpack").Compiler;
394
+ * (config: BuildNextBricksConfig[]): import("webpack").MultiCompiler;
395
+ * }}
396
+ */
397
+ const build = async (config) =>
398
+ webpack(
399
+ await (Array.isArray(config)
400
+ ? Promise.all(config.map((conf) => getWebpackConfig(conf)))
401
+ : getWebpackConfig(config))
402
+ );
403
+
404
+ export default build;
@@ -0,0 +1,34 @@
1
+ export default function getSvgrLoaders(options = {}) {
2
+ return [
3
+ {
4
+ loader: "babel-loader",
5
+ options: {
6
+ rootMode: "upward",
7
+ },
8
+ },
9
+ {
10
+ loader: "@svgr/webpack",
11
+ options: {
12
+ babel: false,
13
+ icon: true,
14
+ svgoConfig: {
15
+ plugins: [
16
+ {
17
+ name: "preset-default",
18
+ params: {
19
+ overrides: {
20
+ // Keep `viewbox`
21
+ removeViewBox: false,
22
+
23
+ convertColors: {
24
+ currentColor: options.convertCurrentColor ?? false,
25
+ },
26
+ },
27
+ },
28
+ },
29
+ ],
30
+ },
31
+ },
32
+ },
33
+ ];
34
+ }
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import build from "./build.js";
2
+ import getSvgrLoaders from "./getSvgrLoaders.js";
2
3
 
3
- export { build };
4
+ export { build, getSvgrLoaders };