diff --git a/examples/getstarted/package.json b/examples/getstarted/package.json index 4dd6089316..099047abbf 100644 --- a/examples/getstarted/package.json +++ b/examples/getstarted/package.json @@ -1,7 +1,7 @@ { "name": "getstarted", "private": true, - "version": "4.2.0-beta.0", + "version": "4.1.4", "description": "A Strapi application.", "scripts": { "develop": "strapi develop", diff --git a/packages/core/admin/package.json b/packages/core/admin/package.json index e6b0794099..e90a5cdb1f 100644 --- a/packages/core/admin/package.json +++ b/packages/core/admin/package.json @@ -28,6 +28,7 @@ "develop:webpack": "cross-env NODE_ENV=development webpack serve --config webpack.config.dev.js --progress profile", "prepublishOnly": "yarn build", "build": "rimraf build && node ./scripts/build.js", + "build:mesure": "rimraf build && cross-env MESURE_BUILD_SPEED=true node ./scripts/build.js", "test": "echo \"no tests yet\"", "test:unit": "jest --verbose", "test:front": "cross-env IS_EE=true jest --config ./jest.config.front.js", @@ -37,10 +38,6 @@ }, "dependencies": { "@babel/core": "7.16.7", - "@babel/plugin-proposal-async-generator-functions": "7.16.7", - "@babel/plugin-proposal-class-properties": "7.16.7", - "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/plugin-transform-modules-commonjs": "7.16.7", "@babel/plugin-transform-runtime": "7.16.7", "@babel/preset-env": "7.16.7", "@babel/preset-react": "7.16.7", @@ -131,7 +128,6 @@ "sift": "13.5.0", "style-loader": "3.3.1", "styled-components": "^5.2.3", - "terser-webpack-plugin": "5.3.0", "webpack": "5.65.0", "webpack-cli": "4.9.1", "webpack-dev-server": "4.7.3", @@ -140,6 +136,7 @@ }, "devDependencies": { "duplicate-dependencies-webpack-plugin": "0.2.0", + "speed-measure-webpack-plugin": "1.5.0", "webpack-bundle-analyzer": "4.4.1" }, "engines": { diff --git a/packages/core/admin/scripts/build.js b/packages/core/admin/scripts/build.js index 664acbeb8f..eaa95e2962 100644 --- a/packages/core/admin/scripts/build.js +++ b/packages/core/admin/scripts/build.js @@ -2,7 +2,10 @@ const path = require('path'); const webpack = require('webpack'); +const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); + const webpackConfig = require('../webpack.config'); +const getPluginsPath = require('../utils/get-plugins-path'); const { getCorePluginsPath, getPluginToInstallPath, @@ -11,20 +14,24 @@ const { const PLUGINS_TO_INSTALL = ['i18n', 'users-permissions']; +// Wrapper that outputs the webpack speed +const smp = new SpeedMeasurePlugin(); + const buildAdmin = async () => { const entry = path.join(__dirname, '..', 'admin', 'src'); const dest = path.join(__dirname, '..', 'build'); const corePlugins = getCorePluginsPath(); const plugins = getPluginToInstallPath(PLUGINS_TO_INSTALL); const allPlugins = { ...corePlugins, ...plugins }; + const pluginsPath = getPluginsPath(); await createPluginsFile(allPlugins); const args = { entry, dest, - cacheDir: __dirname, - pluginsPath: [path.resolve(__dirname, '../../../../packages')], + cacheDir: path.join(__dirname, '..'), + pluginsPath, env: 'production', optimize: true, options: { @@ -33,7 +40,10 @@ const buildAdmin = async () => { }, }; - const compiler = webpack(webpackConfig(args)); + const config = + process.env.MESURE_BUILD_SPEED === 'true' ? smp.wrap(webpackConfig(args)) : webpackConfig(args); + + const compiler = webpack(config); console.log('Building the admin panel'); @@ -73,7 +83,7 @@ buildAdmin() .then(() => { process.exit(); }) - .catch(err => { + .catch((err) => { console.error(err); process.exit(1); }); diff --git a/packages/core/admin/utils/__tests__/get-plugins-path.test.js b/packages/core/admin/utils/__tests__/get-plugins-path.test.js new file mode 100644 index 0000000000..c2ebdefd6b --- /dev/null +++ b/packages/core/admin/utils/__tests__/get-plugins-path.test.js @@ -0,0 +1,23 @@ +'use strict'; + +const getPluginsPath = require('../get-plugins-path'); + +describe('getPluginsPath', () => { + test('should return an array of directories that contains an admin/src/index.js file', () => { + const results = getPluginsPath(); + + expect(results.length).toBeGreaterThan(0); + // Test that the content-type-builder is included + expect(results.findIndex(p => p.includes('/core/content-type-builder/admin'))).not.toEqual(-1); + // Test that the upload is included + expect(results.findIndex(p => p.includes('/core/upload/admin'))).not.toEqual(-1); + // Test that the documentation is included + expect(results.findIndex(p => p.includes('/plugins/documentation/admin'))).not.toEqual(-1); + // Test that the CM is not included + expect(results.findIndex(p => p.includes('/core/content-manager/admin'))).toEqual(-1); + // Test that the admin package is not included + expect(results.findIndex(p => p.includes('/core/admin/admin'))).toEqual(-1); + // Test that the helper-plugin package is not included + expect(results.findIndex(p => p.includes('helper-plugin'))).toEqual(-1); + }); +}); diff --git a/packages/core/admin/utils/get-plugins-path.js b/packages/core/admin/utils/get-plugins-path.js new file mode 100644 index 0000000000..d1da53a384 --- /dev/null +++ b/packages/core/admin/utils/get-plugins-path.js @@ -0,0 +1,26 @@ +'use strict'; + +const { join, resolve } = require('path'); +const fs = require('fs-extra'); +// eslint-disable-next-line node/no-extraneous-require +const glob = require('glob'); + +const getPluginsPath = () => { + const rootPath = resolve(__dirname, '..', join('..', '..', '..', 'packages')); + const corePath = join(rootPath, 'core', '*'); + const pluginsPath = join(rootPath, 'plugins', '*'); + const corePackageDirs = glob.sync(corePath); + const pluginsPackageDirs = glob.sync(pluginsPath); + + const packageDirs = [...corePackageDirs, ...pluginsPackageDirs].filter(dir => { + const isCoreAdmin = dir.includes('packages/core/admin'); + const pathToEntryPoint = join(dir, 'admin', 'src', 'index.js'); + const doesAdminFolderExist = fs.pathExistsSync(pathToEntryPoint); + + return !isCoreAdmin && doesAdminFolderExist; + }); + + return packageDirs.map(dir => resolve(__dirname, '..', join(dir, 'admin', 'src'))); +}; + +module.exports = getPluginsPath; diff --git a/packages/core/admin/webpack.config.dev.js b/packages/core/admin/webpack.config.dev.js index c05aa54a3a..f8e3246c41 100644 --- a/packages/core/admin/webpack.config.dev.js +++ b/packages/core/admin/webpack.config.dev.js @@ -3,7 +3,7 @@ const path = require('path'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const { DuplicateReporterPlugin } = require('duplicate-dependencies-webpack-plugin'); - +const getPluginsPath = require('./utils/get-plugins-path'); const webpackConfig = require('./webpack.config'); module.exports = () => { @@ -19,11 +19,12 @@ module.exports = () => { backend: 'http://localhost:1337', adminPath: '/admin/', }; + const pluginsPath = getPluginsPath(); const args = { entry, cacheDir: __dirname, - pluginsPath: [path.resolve(__dirname, '../../../packages')], + pluginsPath, dest, env, options, @@ -41,27 +42,6 @@ module.exports = () => { return { ...config, - snapshot: { - managedPaths: [ - path.resolve(__dirname, '../content-type-builder'), - path.resolve(__dirname, '../upload'), - path.resolve(__dirname, '../helper-plugin'), - ], - buildDependencies: { - hash: true, - timestamp: true, - }, - module: { - timestamp: true, - }, - resolve: { - timestamp: true, - }, - resolveBuildDependencies: { - hash: true, - timestamp: true, - }, - }, devServer: { port: 4000, diff --git a/packages/core/admin/webpack.config.js b/packages/core/admin/webpack.config.js index 69557d58df..df6196e016 100644 --- a/packages/core/admin/webpack.config.js +++ b/packages/core/admin/webpack.config.js @@ -1,14 +1,14 @@ 'use strict'; const path = require('path'); +const fse = require('fs-extra'); const webpack = require('webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const ForkTsCheckerPlugin = require('fork-ts-checker-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); +const { ESBuildMinifyPlugin } = require('esbuild-loader'); const WebpackBar = require('webpackbar'); const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); -const isWsl = require('is-wsl'); const alias = require('./webpack.alias'); const getClientEnvironment = require('./env'); @@ -79,6 +79,11 @@ module.exports = ({ }); } + // Directly inject a polyfill in the webpack entry point before the entry point + // FIXME: I have noticed a bug regarding the helper-plugin and esbuild-loader + // The only I could fix it was to inject the babel polyfill + const babelPolyfill = '@babel/polyfill/dist/polyfill.min.js'; + return { mode: isProduction ? 'production' : 'development', bail: isProduction ? true : false, @@ -86,7 +91,7 @@ module.exports = ({ experiments: { topLevelAwait: true, }, - entry, + entry: [babelPolyfill, entry], output: { path: dest, publicPath: options.adminPath, @@ -98,28 +103,9 @@ module.exports = ({ optimization: { minimize: optimize, minimizer: [ - // Copied from react-scripts - new TerserPlugin({ - terserOptions: { - parse: { - ecma: 8, - }, - compress: { - ecma: 5, - warnings: false, - comparisons: false, - inline: 2, - }, - mangle: { - safari10: true, - }, - output: { - ecma: 5, - comments: false, - ascii_only: true, - }, - }, - parallel: !isWsl, + new ESBuildMinifyPlugin({ + target: 'es2015', + css: true, // Apply minification to CSS assets }), ], runtimeChunk: true, @@ -128,41 +114,79 @@ module.exports = ({ rules: [ { test: /\.m?js$/, - // TODO remove when plugins are built separately - include: [cacheDir, ...pluginsPath], - use: { - loader: require.resolve('babel-loader'), - options: { - cacheDirectory: true, - cacheCompression: isProduction, - compact: isProduction, - presets: [ - require.resolve('@babel/preset-env'), - require.resolve('@babel/preset-react'), - ], - plugins: [ - [ - require.resolve('@strapi/babel-plugin-switch-ee-ce'), - { - // Imported this tells the custom plugin where to look for the ee folder - roots, - }, - ], - require.resolve('@babel/plugin-proposal-class-properties'), - require.resolve('@babel/plugin-syntax-dynamic-import'), - require.resolve('@babel/plugin-transform-modules-commonjs'), - require.resolve('@babel/plugin-proposal-async-generator-functions'), + include: cacheDir, + oneOf: [ + // Use babel-loader for files that distinct the ee and ce code + // These files have an import Something from 'ee_else_ce/ + { + test(filePath) { + if (!filePath) { + return false; + } - [ - require.resolve('@babel/plugin-transform-runtime'), - { - // absoluteRuntime: true,s - helpers: true, - regenerator: true, - }, - ], - [require.resolve('babel-plugin-styled-components'), { pure: true }], - ], + try { + const fileContent = fse.readFileSync(filePath).toString(); + + if (fileContent.match(/from.* ['"]ee_else_ce\//)) { + return true; + } + + return false; + } catch (e) { + return false; + } + }, + use: { + loader: require.resolve('babel-loader'), + options: { + cacheDirectory: true, + cacheCompression: isProduction, + compact: isProduction, + presets: [ + require.resolve('@babel/preset-env'), + require.resolve('@babel/preset-react'), + ], + plugins: [ + [ + require.resolve('@strapi/babel-plugin-switch-ee-ce'), + { + // Imported this tells the custom plugin where to look for the ee folder + roots, + }, + ], + + [ + require.resolve('@babel/plugin-transform-runtime'), + { + helpers: true, + regenerator: true, + }, + ], + [require.resolve('babel-plugin-styled-components'), { pure: true }], + ], + }, + }, + }, + // Use esbuild-loader for the other files + { + use: { + loader: require.resolve('esbuild-loader'), + options: { + loader: 'jsx', + target: 'es2015', + }, + }, + }, + ], + }, + { + test: /\.m?js$/, + include: pluginsPath, + use: { + loader: require.resolve('esbuild-loader'), + options: { + loader: 'jsx', + target: 'es2015', }, }, }, @@ -212,8 +236,6 @@ module.exports = ({ new HtmlWebpackPlugin({ inject: true, template: path.resolve(__dirname, 'index.html'), - // FIXME - // favicon: path.resolve(__dirname, 'admin/src/favicon.ico'), }), new webpack.DefinePlugin(envVariables), diff --git a/packages/core/helper-plugin/package.json b/packages/core/helper-plugin/package.json index 86e54ab733..b987708c7a 100644 --- a/packages/core/helper-plugin/package.json +++ b/packages/core/helper-plugin/package.json @@ -21,7 +21,6 @@ } ], "main": "build/index.js", - "module": "lib/src/index.js", "files": [ "build" ], diff --git a/yarn.lock b/yarn.lock index 911020b1d6..93bec011c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20922,6 +20922,13 @@ specificity@^0.4.1: resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== +speed-measure-webpack-plugin@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.5.0.tgz#caf2c5bee24ab66c1c7c30e8daa7910497f7681a" + integrity sha512-Re0wX5CtM6gW7bZA64ONOfEPEhwbiSF/vz6e2GvadjuaPrQcHTQdRGsD8+BE7iUOysXH8tIenkPCQBEcspXsNg== + dependencies: + chalk "^4.1.0" + split-array-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/split-array-stream/-/split-array-stream-2.0.0.tgz#85a4f8bfe14421d7bca7f33a6d176d0c076a53b1"