packages/bundles/scripts/tasks.ts (289 lines of code) (raw):

import path from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs-extra'; import { globbySync } from 'globby'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const taskExternals = { // don't bundle caniuse-lite data so users can // update it manually 'caniuse-lite': 'caniuse-lite', '/caniuse-lite(/.*)/': 'caniuse-lite$1', chokidar: 'chokidar', fibers: 'fibers', sass: 'sass', less: 'less', eslint: 'eslint', typescript: 'typescript', postcss: 'postcss', '@swc/core': '@swc/core', 'jest-worker': 'jest-worker', esbuild: 'esbuild', }; const commonDeps = ['terser', 'tapable', 'cssnano', 'terser-webpack-plugin', 'webpack', 'schema-utils', 'lodash', 'postcss-preset-env', 'loader-utils', 'find-up', 'common-path-prefix', 'magic-string']; const webpackDevServerDeps = ['bonjour-service', 'colorette', 'compression', 'connect-history-api-fallback', 'default-gateway', 'express', 'graceful-fs', 'http-proxy-middleware', 'ipaddr.js', 'open', 'p-retry', 'portfinder', 'rimraf', 'selfsigned', 'serve-index', 'sockjs', 'spdy', 'webpack-dev-middleware', 'ws']; commonDeps.concat(webpackDevServerDeps).forEach(dep => taskExternals[dep] = `@ice/bundles/compiled/${dep}`); function replaceDeps(code: string, deps: string[]) { return deps.reduce((acc, curr) => { return acc // cjs .replace(new RegExp(`require\\(["']${curr}["']\\)`, 'g'), `require("${`@ice/bundles/compiled/${curr}`}")`) // esm .replace(new RegExp(`from ["']${curr}["']`, 'g'), `from "${`@ice/bundles/compiled/${curr}`}"`); }, code); } export function filterExternals(externals: Record<string, string>, keys: string[]) { const filterExternals = {}; Object.keys(externals).forEach((externalKey) => { if (!keys.includes(externalKey)) { filterExternals[externalKey] = externals[externalKey]; } }); return filterExternals; } const tasks = [ // simple task ...['cssnano', 'tapable', 'schema-utils', 'lodash', 'less-loader', 'postcss-loader', 'sass-loader', 'css-loader', 'postcss-preset-env', 'postcss-nested', 'postcss-modules', 'postcss-plugin-rpx2vw', 'webpack-bundle-analyzer', 'es-module-lexer', 'terser', 'trusted-cert', 'magic-string', 'eslint-webpack-plugin', 'copy-webpack-plugin', 'cacache', 'ora', 'unplugin', // Dependencies of react-refresh-webpack-plugin. 'loader-utils', 'source-map', 'find-up', 'common-path-prefix', // Dependencies of webpack-dev-server. ...webpackDevServerDeps, ].map((pkgName) => ({ pkgName, externals: taskExternals })), { pkgName: 'esbuild-register', file: 'node_modules/esbuild-register/dist/node.js', externals: taskExternals, bundleName: 'node.js', }, { pkgName: 'unplugin', declaration: false, emptyDir: false, externals: taskExternals, file: 'node_modules/unplugin/dist/webpack/loaders/transform.js', bundleName: 'webpack/loaders/transform.js', }, { pkgName: 'unplugin', declaration: false, emptyDir: false, externals: taskExternals, file: 'node_modules/unplugin/dist/webpack/loaders/load.js', bundleName: 'webpack/loaders/load.js', }, { pkgName: 'unplugin', declaration: false, emptyDir: false, externals: taskExternals, file: 'node_modules/unplugin/dist/rspack/loaders/transform.js', bundleName: 'rspack/loaders/transform.js', }, { pkgName: 'unplugin', declaration: false, emptyDir: false, externals: taskExternals, file: 'node_modules/unplugin/dist/rspack/loaders/load.js', bundleName: 'rspack/loaders/load.js', }, { // pack main package pkgName: 'fork-ts-checker-webpack-plugin', externals: taskExternals, patch: () => { // Hack: ncc will prebundle typescript because of require.resolve('typescript'), overwrite to make it externaled. const targetPath = path.join(__dirname, '../compiled/fork-ts-checker-webpack-plugin/typescript.js'); fs.writeFileSync(targetPath, 'module.exports = require(\'typescript\');'); }, }, { // pack worker file pkgName: 'fork-ts-checker-webpack-plugin', externals: taskExternals, declaration: false, emptyDir: false, file: 'node_modules/fork-ts-checker-webpack-plugin/lib/typescript/worker/get-issues-worker.js', bundleName: 'typescript/worker/get-issues-worker.js', }, { // pack worker file pkgName: 'fork-ts-checker-webpack-plugin', externals: taskExternals, declaration: false, emptyDir: false, file: path.join('node_modules', 'fork-ts-checker-webpack-plugin/lib/typescript/worker/get-dependencies-worker.js'), bundleName: 'typescript/worker/get-dependencies-worker.js', }, { pkgName: 'css-minimizer-webpack-plugin', externals: taskExternals, matchCopyFiles: (data: { resolvePath: string; resolveId: string }): boolean => { const { resolvePath, resolveId } = data; return resolvePath.includes('./utils') && resolveId.includes('css-minimizer-webpack-plugin/dist'); }, }, { pkgName: 'mini-css-extract-plugin', skipCompile: true, patch: () => { // copy packages const pkgPath = path.join(__dirname, '../node_modules/mini-css-extract-plugin'); const targetPath = path.join(__dirname, '../compiled/mini-css-extract-plugin'); const entryPath = path.join(targetPath, 'dist/index.js'); fs.copySync(path.join(pkgPath, 'dist'), path.join(targetPath, 'dist')); fs.copyFileSync(path.join(targetPath, 'index.d.ts'), path.join(targetPath, 'dist/index.d.ts')); fs.writeFileSync(entryPath, fs.readFileSync(entryPath, 'utf-8').replace('schema-utils', '@ice/bundles/compiled/schema-utils/index.js')); }, }, { pkgName: 'terser-webpack-plugin', externals: taskExternals, matchCopyFiles: (data: { resolvePath: string; resolveId: string }): boolean => { const { resolvePath } = data; return resolvePath.endsWith('./utils') || resolvePath.endsWith('.json'); }, }, { pkgName: 'webpack-dev-server', skipCompile: true, patch: () => { // Copy webpack-dev-server while all dependencies has been packed. const pkgPath = path.join(__dirname, '../node_modules/webpack-dev-server'); const filePaths = globbySync(['**/*'], { cwd: pkgPath, ignore: ['node_modules', 'types', 'bin'] }); filePaths.forEach((filePath) => { fs.ensureDirSync(path.join(__dirname, `../compiled/webpack-dev-server/${path.dirname(filePath)}`)); const sourcePath = path.join(pkgPath, filePath); const targetPath = path.join(__dirname, `../compiled/webpack-dev-server/${filePath}`); if (path.extname(filePath) === '.js') { const fileContent = fs.readFileSync(sourcePath, 'utf8'); fs.writeFileSync(targetPath, replaceDeps(fileContent, webpackDevServerDeps.concat(commonDeps))); } else { fs.copyFileSync(sourcePath, targetPath); } }); }, }, { pkgName: '@pmmmwh/react-refresh-webpack-plugin', skipCompile: true, patch: () => { // Copy @pmmmwh/react-refresh-webpack-plugin while all dependencies has been packed. const pkgPath = path.join(__dirname, '../node_modules/@pmmmwh/react-refresh-webpack-plugin'); const filePaths = globbySync(['**/*'], { cwd: pkgPath, ignore: ['node_modules', 'types'] }); filePaths.forEach((filePath) => { fs.ensureDirSync(path.join(__dirname, `../compiled/@pmmmwh/react-refresh-webpack-plugin/${path.dirname(filePath)}`)); const sourcePath = path.join(pkgPath, filePath); const targetPath = path.join(__dirname, `../compiled/@pmmmwh/react-refresh-webpack-plugin/${filePath}`); if (path.extname(filePath) === '.js') { const fileContent = fs.readFileSync(sourcePath, 'utf8'); // Add source-map for react-refresh-webpack-plugin, while other dependencies should pack it. fs.writeFileSync(targetPath, replaceDeps(fileContent, commonDeps.concat('source-map'))); } else { fs.copyFileSync(sourcePath, targetPath); } }); // Overwrite RefreshUtils.js which is customized for ice.js. fs.copyFileSync(path.join(__dirname, '../override/RefreshUtils.js'), path.join(pkgPath, 'lib/runtime/RefreshUtils.js')); }, }, { file: './webpack/bundle', pkgName: 'webpack', bundleName: 'bundle.js', externals: filterExternals(taskExternals, ['webpack']), minify: false, matchCopyFiles: (data: { resolvePath: string }): boolean => { const { resolvePath } = data; return resolvePath.endsWith('.runtime.js'); }, patch: () => { // copy packages const pkgPath = path.join(__dirname, '../node_modules/webpack'); const targetPath = path.join(__dirname, '../compiled/webpack'); fs.copySync(path.join(pkgPath, 'hot'), path.join(targetPath, 'hot')); fs.copySync(path.join(__dirname, '../webpack/packages'), targetPath); }, }, { pkgName: '@rspack/core', skipCompile: true, declaration: false, patch: () => { const pkgPath = path.join(__dirname, '../node_modules/@rspack/core'); const targetPath = path.join(__dirname, '../compiled/@rspack/core'); // Copy the entire directory. // filter out js files and replace with compiled files. const filePaths = globbySync(['**/*'], { cwd: pkgPath, ignore: ['node_modules'] }); const filesAddOverwrite = [ 'dist/util/bindingVersionCheck.js', ]; filePaths.forEach((filePath) => { const sourcePath = path.join(pkgPath, filePath); const targetFilePath = path.join(targetPath, filePath); fs.ensureDirSync(path.dirname(targetFilePath)); if (path.extname(filePath) === '.js') { const matched = filesAddOverwrite.some(filePath => { const matched = sourcePath.split(path.sep).join('/').includes(filePath); if (matched) { fs.copyFileSync(path.join(__dirname, `../override/rspack/${path.basename(filePath)}`), targetFilePath); } return matched; }); if (!matched) { const fileContent = fs.readFileSync(sourcePath, 'utf8'); fs.writeFileSync( targetFilePath, replaceDeps(fileContent, ['tapable', 'schema-utils', 'graceful-fs']) .replace(new RegExp('require\\(["\']@rspack/binding["\']\\)', 'g'), 'require("@ice/pack-binding")'), ); } } else { fs.copyFileSync(sourcePath, targetFilePath); } }); }, }, { pkgName: '@rspack/dev-server', skipCompile: true, patch: () => { // Copy webpack-dev-server while all dependencies has been packed. const pkgPath = path.join(__dirname, '../node_modules/@rspack/dev-server'); const filePaths = globbySync(['**/*'], { cwd: pkgPath, ignore: ['node_modules', 'types', 'bin'] }); filePaths.forEach((filePath) => { fs.ensureDirSync(path.join(__dirname, `../compiled/@rspack/dev-server/${path.dirname(filePath)}`)); const sourcePath = path.join(pkgPath, filePath); const targetPath = path.join(__dirname, `../compiled/@rspack/dev-server/${filePath}`); if (path.extname(filePath) === '.js') { const fileContent = fs.readFileSync(sourcePath, 'utf8'); fs.writeFileSync(targetPath, replaceDeps(fileContent, webpackDevServerDeps.concat([...commonDeps, '@rspack/core', 'webpack-dev-server'])) .replace(/webpack-dev-server\//g, '@ice/bundles/compiled/webpack-dev-server/') .replace(/@rspack\/core\//g, '@ice/bundles/compiled/@rspack/core/') .replace(/@rspack\/dev-server\//g, '@ice/bundles/compiled/@rspack/dev-server/'), ); } else { fs.copyFileSync(sourcePath, targetPath); } }); }, }, { pkgName: '@rspack/plugin-react-refresh', skipCompile: true, patch: () => { const pkgPath = path.join(__dirname, '../node_modules/@rspack/plugin-react-refresh'); const filePaths = globbySync(['**/*'], { cwd: pkgPath, ignore: ['node_modules'] }); filePaths.forEach((filePath) => { fs.ensureDirSync(path.join(__dirname, `../compiled/@rspack/plugin-react-refresh/${path.dirname(filePath)}`)); const sourcePath = path.join(pkgPath, filePath); const targetPath = path.join(__dirname, `../compiled/@rspack/plugin-react-refresh/${filePath}`); if (path.extname(filePath) === '.js') { const fileContent = fs.readFileSync(sourcePath, 'utf8'); fs.writeFileSync(targetPath, replaceDeps(fileContent, webpackDevServerDeps.concat([ ...commonDeps, '@rspack/core', ])), ); } else { fs.copyFileSync(sourcePath, targetPath); } }); // Overwrite RefreshUtils.js which is customized for ice.js. fs.copyFileSync( path.join(__dirname, '../override/RefreshUtils.js'), path.join(__dirname, '../compiled/@rspack/plugin-react-refresh/client/refreshUtils.js'), ); }, }, ]; export default tasks;