@gravity-ui/app-builder 0.5.6 → 0.6.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.1](https://github.com/gravity-ui/app-builder/compare/v0.6.0...v0.6.1) (2023-07-24)
4
+
5
+
6
+ ### Features
7
+
8
+ * **css:** use Lightning CSS ([#52](https://github.com/gravity-ui/app-builder/issues/52)) ([d16cd09](https://github.com/gravity-ui/app-builder/commit/d16cd09067276eee9b0952f2c198e6e4e6365c3d))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **s3-client:** add charset to content type ([#50](https://github.com/gravity-ui/app-builder/issues/50)) ([8b1a944](https://github.com/gravity-ui/app-builder/commit/8b1a944d675e0f1b88f80fa43d0929148ce82a05))
14
+
15
+ ## [0.6.0](https://github.com/gravity-ui/app-builder/compare/v0.5.6...v0.6.0) (2023-07-23)
16
+
17
+
18
+ ### Features
19
+
20
+ * add caching to worker loader ([#48](https://github.com/gravity-ui/app-builder/issues/48)) ([c7db4fb](https://github.com/gravity-ui/app-builder/commit/c7db4fb2786729a173e5fbe0f62c679639b9a99a))
21
+
3
22
  ## [0.5.6](https://github.com/gravity-ui/app-builder/compare/v0.5.5...v0.5.6) (2023-07-21)
4
23
 
5
24
 
package/README.md CHANGED
@@ -232,6 +232,7 @@ With this `{rootDir}/src/ui/tsconfig.json`:
232
232
  - `highlight.js` (`string[]`) — list of language names to include, e.g. `['javascript', 'python', 'bash']`;
233
233
  - `locale`: (`string[]=['ru']`) — list of `moment.js` or `day.js` locales to include, e.g. `['de', 'es']`. Locale `En` is always present.
234
234
  - `safari10` (`boolean`) — Enables `safari10` terser's option. [Terser options](https://github.com/terser/terser#minify-options)
235
+ - `transformCssWithLightningCss` (`boolean`) — use [Lighting CSS](https://lightningcss.dev) to transform and minimize css instead of PostCSS and cssnano
235
236
 
236
237
  ##### Monaco editor support
237
238
 
@@ -7,7 +7,6 @@ export declare class ControllableScript {
7
7
  isRunning: boolean;
8
8
  private process?;
9
9
  private script;
10
- private tmpFileName;
11
10
  private debugInfo;
12
11
  constructor(script: string, debugInfo: IDebugInfo | null);
13
12
  start(): void;
@@ -22,27 +22,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.ControllableScript = void 0;
30
27
  const utils_1 = require("./utils");
31
- const path_1 = __importDefault(require("path"));
32
28
  const fs = __importStar(require("fs-extra"));
33
29
  const execa = __importStar(require("execa"));
30
+ const utils_2 = require("../utils");
34
31
  class ControllableScript {
35
32
  constructor(script, debugInfo) {
36
33
  this.isRunning = false;
37
34
  this.script = '';
38
- this.tmpFileName = '';
39
35
  this.script = script;
40
36
  this.debugInfo = debugInfo;
41
37
  }
42
38
  start() {
43
39
  const args = [];
44
- this.tmpFileName = (0, utils_1.tmpNameSync)(path_1.default.join(process.cwd(), 'node_modules'));
45
- fs.outputFileSync(this.tmpFileName, this.script);
40
+ const tmpFileName = (0, utils_1.tmpNameSync)((0, utils_2.getCacheDir)());
41
+ fs.outputFileSync(tmpFileName, this.script);
46
42
  this.isRunning = true;
47
43
  // Passing --inspect isn't necessary for the child process to launch a port, but it allows some editors to automatically attach
48
44
  if (this.debugInfo) {
@@ -53,7 +49,7 @@ class ControllableScript {
53
49
  args.push(`--inspect=${this.debugInfo.port}`);
54
50
  }
55
51
  }
56
- this.process = execa.node(this.tmpFileName, args, {
52
+ this.process = execa.node(tmpFileName, args, {
57
53
  env: {
58
54
  ...process.env,
59
55
  },
@@ -63,6 +59,9 @@ class ControllableScript {
63
59
  this.process.on('unhandledRejection', () => {
64
60
  this.stop('SIGABRT');
65
61
  });
62
+ this.process.on('exit', () => {
63
+ fs.unlinkSync(tmpFileName);
64
+ });
66
65
  }
67
66
  async stop(signal = null, code) {
68
67
  if (!this.process) {
@@ -99,7 +98,6 @@ class ControllableScript {
99
98
  this.process.removeAllListeners();
100
99
  }
101
100
  this.process = undefined;
102
- fs.unlinkSync(this.tmpFileName);
103
101
  resolve();
104
102
  });
105
103
  });
@@ -167,6 +167,8 @@ export interface ClientConfig {
167
167
  newWebWorkerSyntax?: boolean;
168
168
  babelCacheDirectory?: boolean | string;
169
169
  cache?: boolean | FileCacheOptions | MemoryCacheOptions;
170
+ /** Use [Lighting CSS](https://lightningcss.dev) to transform and minimize css instead of PostCSS and cssnano*/
171
+ transformCssWithLightningCss?: boolean;
170
172
  }
171
173
  interface CdnUploadConfig {
172
174
  bucket: string;
@@ -84,16 +84,27 @@ async function detectContentTypeFromBuffer(buffer) {
84
84
  if (!type) {
85
85
  throw Error('Cannot detect content type for buffer');
86
86
  }
87
- return type.mime;
87
+ let contentType = type.mime;
88
+ // use default charset for content type
89
+ const charset = mime.charset(contentType);
90
+ if (charset) {
91
+ contentType += `; charset=${charset.toLowerCase()}`;
92
+ }
93
+ return contentType;
88
94
  }
89
95
  function detectContentTypeFromExt(filePath) {
90
96
  // Compressed file Content-type must be the same as original file Content-type
91
97
  if (filePath.endsWith('.br') || filePath.endsWith('.gz')) {
92
98
  filePath = filePath.slice(0, -3);
93
99
  }
94
- const type = mime.lookup(filePath);
95
- if (!type) {
100
+ let contentType = mime.lookup(filePath);
101
+ if (!contentType) {
96
102
  throw Error(`Cannot detect content type for file ${filePath}`);
97
103
  }
98
- return type;
104
+ // use default charset for content type
105
+ const charset = mime.charset(contentType);
106
+ if (charset) {
107
+ contentType += `; charset=${charset.toLowerCase()}`;
108
+ }
109
+ return contentType;
99
110
  }
@@ -1,2 +1,3 @@
1
1
  export declare function createRunFolder(): void;
2
2
  export declare function shouldCompileTarget(target: 'client' | 'server' | undefined, targetName: string): boolean;
3
+ export declare function getCacheDir(): string;
@@ -3,8 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.shouldCompileTarget = exports.createRunFolder = void 0;
6
+ exports.getCacheDir = exports.shouldCompileTarget = exports.createRunFolder = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const find_cache_dir_1 = __importDefault(require("find-cache-dir"));
8
10
  const paths_1 = __importDefault(require("./paths"));
9
11
  function createRunFolder() {
10
12
  const runPath = paths_1.default.appRun;
@@ -17,3 +19,7 @@ function shouldCompileTarget(target, targetName) {
17
19
  return target === undefined || target === targetName;
18
20
  }
19
21
  exports.shouldCompileTarget = shouldCompileTarget;
22
+ function getCacheDir() {
23
+ return (0, find_cache_dir_1.default)({ name: '@gravity-ui/app-builder', create: true }) || os_1.default.tmpdir();
24
+ }
25
+ exports.getCacheDir = getCacheDir;
@@ -36,9 +36,7 @@ const clean_webpack_plugin_1 = require("clean-webpack-plugin");
36
36
  const webpack_manifest_plugin_1 = require("webpack-manifest-plugin");
37
37
  const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
38
38
  const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
39
- const css_minimizer_webpack_plugin_1 = __importDefault(require("css-minimizer-webpack-plugin"));
40
39
  const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
41
- const postcss_preset_env_1 = __importDefault(require("postcss-preset-env"));
42
40
  const webpack_assets_manifest_1 = __importDefault(require("webpack-assets-manifest"));
43
41
  const react_refresh_webpack_plugin_1 = __importDefault(require("@pmmmwh/react-refresh-webpack-plugin"));
44
42
  const moment_timezone_data_webpack_plugin_1 = __importDefault(require("moment-timezone-data-webpack-plugin"));
@@ -348,16 +346,20 @@ function createStylesRule({ isEnvDevelopment, isEnvProduction, config, }) {
348
346
  importLoaders: 2,
349
347
  },
350
348
  });
351
- loaders.push({
352
- loader: require.resolve('postcss-loader'),
353
- options: {
354
- sourceMap: !config.disableSourceMapGeneration,
355
- postcssOptions: {
356
- config: false,
357
- plugins: [(0, postcss_preset_env_1.default)({ enableClientSidePolyfills: false })],
349
+ if (!config.transformCssWithLightningCss) {
350
+ loaders.push({
351
+ loader: require.resolve('postcss-loader'),
352
+ options: {
353
+ sourceMap: !config.disableSourceMapGeneration,
354
+ postcssOptions: {
355
+ config: false,
356
+ plugins: [
357
+ [require.resolve('postcss-preset-env'), { enableClientSidePolyfills: false }],
358
+ ],
359
+ },
358
360
  },
359
- },
360
- });
361
+ });
362
+ }
361
363
  loaders.push({
362
364
  loader: require.resolve('resolve-url-loader'),
363
365
  options: {
@@ -609,16 +611,6 @@ function configurePlugins(options) {
609
611
  chunkFilename: 'css/[name].[contenthash:8].chunk.css',
610
612
  ignoreOrder: true,
611
613
  }));
612
- plugins.push(new css_minimizer_webpack_plugin_1.default({
613
- minimizerOptions: {
614
- preset: [
615
- 'default',
616
- {
617
- svgo: false,
618
- },
619
- ],
620
- },
621
- }));
622
614
  if (config.analyzeBundle === 'true') {
623
615
  plugins.push(new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
624
616
  openAnalyzer: false,
@@ -691,7 +683,7 @@ function configurePlugins(options) {
691
683
  }
692
684
  return plugins;
693
685
  }
694
- function configureOptimization({ isEnvProduction, config, }) {
686
+ function configureOptimization({ config }) {
695
687
  const configVendors = config.vendors ?? [];
696
688
  const vendorsList = [
697
689
  'react',
@@ -708,7 +700,6 @@ function configureOptimization({ isEnvProduction, config, }) {
708
700
  ...configVendors,
709
701
  ];
710
702
  const optimization = {
711
- minimize: isEnvProduction && !config.reactProfiling,
712
703
  splitChunks: {
713
704
  chunks: 'all',
714
705
  cacheGroups: {
@@ -721,16 +712,48 @@ function configureOptimization({ isEnvProduction, config, }) {
721
712
  },
722
713
  },
723
714
  runtimeChunk: 'single',
715
+ minimizer: [
716
+ (compiler) => {
717
+ // CssMinimizerWebpackPlugin works with MiniCSSExtractPlugin, so only relevant for production builds.
718
+ // Lazy load the CssMinimizerPlugin plugin
719
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
720
+ if (config.transformCssWithLightningCss) {
721
+ const lightningCss = require('lightningcss');
722
+ const browserslist = require('browserslist');
723
+ new CssMinimizerPlugin({
724
+ minify: CssMinimizerPlugin.lightningCssMinify,
725
+ minimizerOptions: {
726
+ targets: lightningCss.browserslistToTargets(browserslist()),
727
+ },
728
+ }).apply(compiler);
729
+ }
730
+ else {
731
+ new CssMinimizerPlugin({
732
+ minimizerOptions: {
733
+ preset: [
734
+ 'default',
735
+ {
736
+ svgo: false,
737
+ },
738
+ ],
739
+ },
740
+ }).apply(compiler);
741
+ }
742
+ },
743
+ (compiler) => {
744
+ // Lazy load the Terser plugin
745
+ const TerserPlugin = require('terser-webpack-plugin');
746
+ new TerserPlugin({
747
+ terserOptions: {
748
+ compress: {
749
+ passes: 2,
750
+ },
751
+ safari10: config.safari10,
752
+ mangle: !config.reactProfiling,
753
+ },
754
+ }).apply(compiler);
755
+ },
756
+ ],
724
757
  };
725
- if (config.safari10) {
726
- const TerserPlugin = require('terser-webpack-plugin');
727
- optimization.minimizer = [
728
- new TerserPlugin({
729
- terserOptions: {
730
- safari10: true,
731
- },
732
- }),
733
- ];
734
- }
735
758
  return optimization;
736
759
  }
@@ -11,6 +11,7 @@ const WebWorkerTemplatePlugin_1 = __importDefault(require("webpack/lib/webworker
11
11
  const FetchCompileWasmPlugin_1 = __importDefault(require("webpack/lib/web/FetchCompileWasmPlugin"));
12
12
  const FetchCompileAsyncWasmPlugin_1 = __importDefault(require("webpack/lib/web/FetchCompileAsyncWasmPlugin"));
13
13
  const paths_1 = __importDefault(require("../../paths"));
14
+ const pluginId = 'APP_BUILDER_WORKER_LOADER';
14
15
  const publicPath = node_path_1.default.resolve(__dirname, 'public-path.worker.js');
15
16
  const pitch = function (request) {
16
17
  this.cacheable(false);
@@ -18,7 +19,7 @@ const pitch = function (request) {
18
19
  throw new Error('Something went wrong');
19
20
  }
20
21
  const compilerOptions = this._compiler.options;
21
- const logger = this.getLogger('APP_BUILDER_WORKER_LOADER');
22
+ const logger = this.getLogger(pluginId);
22
23
  if (compilerOptions.output.globalObject === 'window') {
23
24
  logger.warn('Warning (app-builder-worker-loader): output.globalObject is set to "window". It should be set to "self" or "this" to support HMR in Workers.');
24
25
  }
@@ -67,23 +68,39 @@ const pitch = function (request) {
67
68
  .join('\n');
68
69
  return cb(new Error('Child compilation failed:\n' + errorDetails));
69
70
  }
70
- const contents = compilation.assets[filename]?.source();
71
- const mapFile = `${filename}.map`;
72
- let map = compilation.assets[mapFile]?.source();
73
- if (map) {
74
- const sourceMap = JSON.parse(map.toString());
75
- if (Array.isArray(sourceMap.sources)) {
76
- sourceMap.sources = sourceMap.sources.map((pathname) => pathname.replace(/webpack:\/\/[^/]+\//, 'webpack://'));
71
+ const cache = workerCompiler.getCache(pluginId);
72
+ const cacheIdent = request;
73
+ const cacheETag = cache.getLazyHashedEtag(compilation.assets[filename]);
74
+ return cache.get(cacheIdent, cacheETag, (getCacheError, cacheContent) => {
75
+ if (getCacheError) {
76
+ return cb(getCacheError);
77
77
  }
78
- map = JSON.stringify(sourceMap);
79
- }
80
- for (const [assetName, asset] of Object.entries(compilation.assets)) {
81
- if ([filename, mapFile].includes(assetName)) {
82
- continue;
78
+ if (cacheContent) {
79
+ return cb(null, cacheContent.content, cacheContent.map);
83
80
  }
84
- workerCompiler.parentCompilation?.emitAsset(assetName, asset, compilation.assetsInfo.get(assetName));
85
- }
86
- return cb(null, contents, map?.toString());
81
+ const content = compilation.assets[filename]?.source();
82
+ const mapFile = `${filename}.map`;
83
+ let map = compilation.assets[mapFile]?.source();
84
+ if (map) {
85
+ const sourceMap = JSON.parse(map.toString());
86
+ if (Array.isArray(sourceMap.sources)) {
87
+ sourceMap.sources = sourceMap.sources.map((pathname) => pathname.replace(/webpack:\/\/[^/]+\//, 'webpack://'));
88
+ }
89
+ map = JSON.stringify(sourceMap);
90
+ }
91
+ for (const [assetName, asset] of Object.entries(compilation.assets)) {
92
+ if ([filename, mapFile].includes(assetName)) {
93
+ continue;
94
+ }
95
+ workerCompiler.parentCompilation?.emitAsset(assetName, asset, compilation.assetsInfo.get(assetName));
96
+ }
97
+ return cache.store(cacheIdent, cacheETag, { content, map: map?.toString() }, (storeCacheError) => {
98
+ if (storeCacheError) {
99
+ return cb(storeCacheError);
100
+ }
101
+ return cb(null, content, map?.toString());
102
+ });
103
+ });
87
104
  });
88
105
  };
89
106
  exports.pitch = pitch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/app-builder",
3
- "version": "0.5.6",
3
+ "version": "0.6.1",
4
4
  "description": "Develop and build your React client-server projects, powered by typescript and webpack",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -74,6 +74,7 @@
74
74
  "babel-plugin-inline-react-svg": "^2.0.2",
75
75
  "babel-plugin-lodash": "^3.3.4",
76
76
  "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
77
+ "browserslist": "^4.21.9",
77
78
  "chalk": "^4.1.2",
78
79
  "circular-dependency-plugin": "^5.2.2",
79
80
  "clean-webpack-plugin": "^4.0.0",
@@ -82,19 +83,21 @@
82
83
  "cosmiconfig": "^8.1.3",
83
84
  "cosmiconfig-typescript-loader": "^4.3.0",
84
85
  "css-loader": "^6.8.1",
85
- "css-minimizer-webpack-plugin": "^5.0.0",
86
- "dotenv": "^16.1.4",
86
+ "css-minimizer-webpack-plugin": "^5.0.1",
87
+ "dotenv": "^16.3.1",
87
88
  "execa": "^5.1.1",
88
89
  "fast-glob": "^3.2.12",
89
90
  "file-type": "^16.5.3",
91
+ "find-cache-dir": "^3.3.2",
90
92
  "fork-ts-checker-webpack-plugin": "^8.0.0",
91
93
  "fs-extra": "^11.1.1",
92
94
  "get-port": "^5.1.1",
95
+ "lightningcss": "^1.21.5",
93
96
  "lodash": "^4.17.21",
94
97
  "mime-types": "^2.1.35",
95
98
  "mini-css-extract-plugin": "^2.7.6",
96
99
  "moment-timezone-data-webpack-plugin": "^1.5.1",
97
- "nodemon": "^2.0.22",
100
+ "nodemon": "^3.0.1",
98
101
  "p-map": "^4.0.0",
99
102
  "p-queue": "^6.6.2",
100
103
  "pino-pretty": "^10.0.0",
@@ -108,16 +111,17 @@
108
111
  "rimraf": "^5.0.0",
109
112
  "sass": "^1.62.1",
110
113
  "sass-loader": "^13.3.1",
111
- "semver": "^7.5.2",
114
+ "semver": "^7.5.4",
112
115
  "signal-exit": "^3.0.7",
113
116
  "source-map-loader": "^4.0.1",
114
117
  "strip-ansi": "^6.0.1",
115
118
  "style-loader": "^3.3.3",
116
119
  "svgo": "^3.0.2",
117
120
  "ts-node": "10.9.1",
118
- "tslib": "^2.5.0",
119
- "typescript": "^5.1.3",
120
- "webpack": "^5.85.1",
121
+ "tslib": "^2.6.0",
122
+ "terser-webpack-plugin": "5.3.9",
123
+ "typescript": "^5.1.6",
124
+ "webpack": "^5.88.1",
121
125
  "webpack-assets-manifest": "^5.1.0",
122
126
  "webpack-bundle-analyzer": "^4.9.0",
123
127
  "webpack-dev-server": "^4.15.0",
@@ -133,6 +137,7 @@
133
137
  "@gravity-ui/tsconfig": "^1.0.0",
134
138
  "@types/circular-dependency-plugin": "^5.0.5",
135
139
  "@types/common-tags": "^1.8.1",
140
+ "@types/find-cache-dir": "^3.2.1",
136
141
  "@types/fs-extra": "^11.0.1",
137
142
  "@types/jest": "^29.5.2",
138
143
  "@types/lodash": "^4.14.195",