diff --git a/app/javascript/entrypoints/index.html b/app/javascript/entrypoints/index.html deleted file mode 100644 index 025030ba46..0000000000 --- a/app/javascript/entrypoints/index.html +++ /dev/null @@ -1,8 +0,0 @@ - -
- - - - - - diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 4c2fe5682b..0000000000 --- a/babel.config.js +++ /dev/null @@ -1,80 +0,0 @@ -module.exports = (api) => { - const env = api.env(); - - const reactOptions = { - development: false, - runtime: 'automatic', - }; - - const envOptions = { - useBuiltIns: "usage", - corejs: { version: "3.30" }, - debug: false, - include: [ - 'transform-numeric-separator', - 'transform-optional-chaining', - 'transform-nullish-coalescing-operator', - 'transform-class-properties', - ], - }; - - const plugins = [ - ['formatjs'], - 'preval', - ]; - - switch (env) { - case 'production': - plugins.push(...[ - 'lodash', - [ - 'transform-react-remove-prop-types', - { - mode: 'remove', - removeImport: true, - additionalLibraries: [ - 'react-immutable-proptypes', - ], - }, - ], - '@babel/transform-react-inline-elements', - [ - '@babel/transform-runtime', - { - helpers: true, - regenerator: false, - useESModules: true, - }, - ], - ]); - break; - - case 'development': - reactOptions.development = true; - envOptions.debug = true; - - // We need Babel to not inject polyfills in dev, as this breaks `preval` files - envOptions.useBuiltIns = false; - envOptions.corejs = undefined; - break; - } - - const config = { - presets: [ - '@babel/preset-typescript', - ['@babel/react', reactOptions], - ['@babel/env', envOptions], - ], - plugins, - overrides: [ - { - test: [/tesseract\.js/, /fuzzysort\.js/], - presets: [ - ['@babel/env', { ...envOptions, modules: 'commonjs' }], - ], - }, - ], - }; - - return config; -}; diff --git a/config/vite/plugin-manifest-sri.ts b/config/vite/plugin-manifest-sri.ts index 4c768abfa5..e940e35a63 100644 --- a/config/vite/plugin-manifest-sri.ts +++ b/config/vite/plugin-manifest-sri.ts @@ -13,13 +13,6 @@ export interface Options { * @default ['sha384'] */ algorithms?: Algorithm[]; - - /** - * Path of the manifest files that should be read and augmented with the - * integrity hash, relative to `outDir`. - * @default ['manifest.json', 'manifest-assets.json'] - */ - manifestPaths?: string[]; } declare module 'vite' { @@ -29,26 +22,14 @@ declare module 'vite' { } export function manifestSRI(options: Options = {}): Plugin { - const { - algorithms = ['sha384'], - manifestPaths = [ - '.vite/manifest.json', - '.vite/manifest-assets.json', - 'manifest.json', - 'manifest-assets.json', - ], - } = options; + const { algorithms = ['sha384'] } = options; return { name: 'vite-plugin-manifest-sri', apply: 'build', enforce: 'post', async writeBundle({ dir }) { - await Promise.all( - manifestPaths.map((path) => - augmentManifest(path, algorithms, dir ?? ''), - ), - ); + await augmentManifest('manifest.json', algorithms, dir ?? ''); }, }; } diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js deleted file mode 100644 index a647b45992..0000000000 --- a/config/webpack/configuration.js +++ /dev/null @@ -1,28 +0,0 @@ -// Common configuration for webpacker loaded from config/webpacker.yml - -const { readFileSync } = require('fs'); -const { resolve } = require('path'); -const { env } = require('process'); - -const { load } = require('js-yaml'); - -const configPath = resolve('config', 'webpacker.yml'); -const settings = load(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV]; - -const themePath = resolve('config', 'themes.yml'); -const themes = load(readFileSync(themePath), 'utf8'); - -const output = { - path: resolve('public', settings.public_output_path), - publicPath: `/${settings.public_output_path}/`, -}; - -module.exports = { - settings, - themes, - env: { - NODE_ENV: env.NODE_ENV, - PUBLIC_OUTPUT_PATH: settings.public_output_path, - }, - output, -}; diff --git a/config/webpack/development.js b/config/webpack/development.js deleted file mode 100644 index e3fbfe4b9d..0000000000 --- a/config/webpack/development.js +++ /dev/null @@ -1,62 +0,0 @@ -// Note: You must restart bin/webpack-dev-server for changes to take effect - -const { merge } = require('webpack-merge'); - -const { settings, output } = require('./configuration'); -const sharedConfig = require('./shared'); - -const watchOptions = {}; - -if (process.env.VAGRANT) { - // If we are in Vagrant, we can't rely on inotify to update us with changed - // files, so we must poll instead. Here, we poll every second to see if - // anything has changed. - watchOptions.poll = 1000; -} - -module.exports = merge(sharedConfig, { - mode: 'development', - cache: true, - devtool: 'cheap-module-eval-source-map', - - stats: { - errorDetails: true, - }, - - output: { - pathinfo: true, - }, - - devServer: { - clientLogLevel: 'none', - compress: settings.dev_server.compress, - quiet: settings.dev_server.quiet, - disableHostCheck: settings.dev_server.disable_host_check, - host: settings.dev_server.host, - port: settings.dev_server.port, - https: settings.dev_server.https, - hot: settings.dev_server.hmr, - contentBase: output.path, - inline: settings.dev_server.inline, - useLocalIp: settings.dev_server.use_local_ip, - public: settings.dev_server.public, - publicPath: output.publicPath, - historyApiFallback: { - disableDotRule: true, - }, - headers: settings.dev_server.headers, - overlay: settings.dev_server.overlay, - stats: { - entrypoints: false, - errorDetails: false, - modules: false, - moduleTrace: false, - }, - watchOptions: Object.assign( - {}, - settings.dev_server.watch_options, - watchOptions, - ), - writeToDisk: filePath => /ocr/.test(filePath), - }, -}); diff --git a/config/webpack/production.js b/config/webpack/production.js deleted file mode 100644 index 0b811f349f..0000000000 --- a/config/webpack/production.js +++ /dev/null @@ -1,74 +0,0 @@ -// Note: You must restart bin/webpack-dev-server for changes to take effect - -const { createHash } = require('crypto'); -const { readFileSync } = require('fs'); -const { resolve } = require('path'); - -const CompressionPlugin = require('compression-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); -const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); -const { merge } = require('webpack-merge'); -const { InjectManifest } = require('workbox-webpack-plugin'); - -const sharedConfig = require('./shared'); - -const root = resolve(__dirname, '..', '..'); - -module.exports = merge(sharedConfig, { - mode: 'production', - devtool: 'source-map', - stats: 'normal', - bail: true, - optimization: { - minimize: true, - minimizer: [ - new TerserPlugin({ - cache: true, - parallel: true, - sourceMap: true, - }), - ], - }, - - plugins: [ - new CompressionPlugin({ - filename: '[path][base].gz[query]', - cache: true, - test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/, - }), - new CompressionPlugin({ - filename: '[path][base].br[query]', - algorithm: 'brotliCompress', - cache: true, - test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/, - }), - new BundleAnalyzerPlugin({ // generates report.html - analyzerMode: 'static', - openAnalyzer: false, - logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout - }), - new InjectManifest({ - additionalManifestEntries: ['1f602.svg', 'sheet_15_1.png'].map((filename) => { - const path = resolve(root, 'public', 'emoji', filename); - const body = readFileSync(path); - const md5 = createHash('md5'); - - md5.update(body); - - return { - revision: md5.digest('hex'), - url: `/emoji/${filename}`, - }; - }), - exclude: [ - /(?:base|extra)_polyfills-.*\.js$/, - /locale_.*\.js$/, - /mailer-.*\.(?:css|js)$/, - ], - include: [/\.js$/, /\.css$/], - maximumFileSizeToCacheInBytes: 2 * 1_024 * 1_024, // 2 MiB - swDest: resolve(root, 'public', 'packs', 'sw.js'), - swSrc: resolve(root, 'app', 'javascript', 'mastodon', 'service_worker', 'entry.js'), - }), - ], -}); diff --git a/config/webpack/rules/babel.js b/config/webpack/rules/babel.js deleted file mode 100644 index 76e41f3df0..0000000000 --- a/config/webpack/rules/babel.js +++ /dev/null @@ -1,28 +0,0 @@ -const { join, resolve } = require('path'); - -const { env, settings } = require('../configuration'); - -// Those modules contain modern ES code that need to be transpiled for Webpack to process it -const nodeModulesToProcess = [ - '@reduxjs', 'fuzzysort', 'toygrad', '@react-spring' -]; - -module.exports = { - test: /\.(js|jsx|mjs|ts|tsx)$/, - include: [ - settings.source_path, - ...settings.resolved_paths, - ...nodeModulesToProcess.map(p => resolve(`node_modules/${p}`)), - ].map(p => resolve(p)), - exclude: new RegExp('node_modules\\/(?!(' + nodeModulesToProcess.join('|')+')\\/).*'), - use: [ - { - loader: 'babel-loader', - options: { - cacheDirectory: join(settings.cache_path, 'babel-loader'), - cacheCompression: env.NODE_ENV === 'production', - compact: env.NODE_ENV === 'production', - }, - }, - ], -}; diff --git a/config/webpack/rules/css.js b/config/webpack/rules/css.js deleted file mode 100644 index bc1f42c134..0000000000 --- a/config/webpack/rules/css.js +++ /dev/null @@ -1,28 +0,0 @@ -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); - -module.exports = { - test: /\.s?css$/i, - use: [ - MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - sourceMap: true, - importLoaders: 2, - }, - }, - { - loader: 'postcss-loader', - options: { - sourceMap: true, - }, - }, - { - loader: 'sass-loader', - options: { - implementation: require('sass'), - sourceMap: true, - }, - }, - ], -}; diff --git a/config/webpack/rules/file.js b/config/webpack/rules/file.js deleted file mode 100644 index 71ae2afe03..0000000000 --- a/config/webpack/rules/file.js +++ /dev/null @@ -1,22 +0,0 @@ -const { join } = require('path'); - -const { settings } = require('../configuration'); - -module.exports = { - test: new RegExp(`(${settings.static_assets_extensions.join('|')})$`, 'i'), - exclude: [/material-icons/, /svg-icons/], - use: [ - { - loader: 'file-loader', - options: { - name(file) { - if (file.includes(settings.source_path)) { - return 'media/[path][name]-[hash].[ext]'; - } - return 'media/[folder]/[name]-[hash:8].[ext]'; - }, - context: join(settings.source_path), - }, - }, - ], -}; diff --git a/config/webpack/rules/index.js b/config/webpack/rules/index.js deleted file mode 100644 index 4be59f1b64..0000000000 --- a/config/webpack/rules/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const babel = require('./babel'); -const css = require('./css'); -const file = require('./file'); -const materialIcons = require('./material_icons'); -const tesseract = require('./tesseract'); - -// Webpack loaders are processed in reverse order -// https://webpack.js.org/concepts/loaders/#loader-features -// Lastly, process static files using file loader -module.exports = { - materialIcons, - file, - tesseract, - css, - babel, -}; diff --git a/config/webpack/rules/mark.js b/config/webpack/rules/mark.js deleted file mode 100644 index e62a526b02..0000000000 --- a/config/webpack/rules/mark.js +++ /dev/null @@ -1,8 +0,0 @@ -if (process.env.NODE_ENV === 'production') { - module.exports = {}; -} else { - module.exports = { - test: /\.js$/, - loader: 'mark-loader', - }; -} diff --git a/config/webpack/rules/material_icons.js b/config/webpack/rules/material_icons.js deleted file mode 100644 index 65045036c3..0000000000 --- a/config/webpack/rules/material_icons.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - test: /\.svg$/, - include: [/material-icons/, /svg-icons/], - issuer: /\.[jt]sx?$/, - use: [ - { - loader: '@svgr/webpack', - options: { - svgo: false, - titleProp: true, - }, - }, - ], -}; diff --git a/config/webpack/rules/tesseract.js b/config/webpack/rules/tesseract.js deleted file mode 100644 index 746fa55dfe..0000000000 --- a/config/webpack/rules/tesseract.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - test: [ - /tesseract\.js\/dist\/worker\.min\.js$/, - /tesseract\.js\/dist\/worker\.min\.js\.map$/, - /tesseract\.js-core\/tesseract-core\.wasm\.js$/, - ], - use: { - loader: 'file-loader', - options: { - name: 'ocr/[name]-[hash].[ext]', - }, - }, -}; diff --git a/config/webpack/shared.js b/config/webpack/shared.js deleted file mode 100644 index 8e77a840a5..0000000000 --- a/config/webpack/shared.js +++ /dev/null @@ -1,113 +0,0 @@ -// Note: You must restart bin/webpack-dev-server for changes to take effect - -const { basename, dirname, join, relative, resolve } = require('path'); - -const CircularDependencyPlugin = require('circular-dependency-plugin'); -const { sync } = require('glob'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const extname = require('path-complete-extname'); -const webpack = require('webpack'); -const AssetsManifestPlugin = require('webpack-assets-manifest'); - -const { env, settings, themes, output } = require('./configuration'); -const rules = require('./rules'); - -const extensionGlob = `**/*{${settings.extensions.join(',')}}*`; -const entryPath = join(settings.source_path, settings.source_entry_path); -const packPaths = sync(join(entryPath, extensionGlob)); - -module.exports = { - entry: Object.assign( - packPaths.reduce((map, entry) => { - const localMap = map; - const namespace = relative(join(entryPath), dirname(entry)); - localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); - return localMap; - }, {}), - Object.keys(themes).reduce((themePaths, name) => { - themePaths[name] = resolve(join(settings.source_path, themes[name])); - return themePaths; - }, {}), - ), - - output: { - filename: 'js/[name]-[chunkhash].js', - chunkFilename: 'js/[name]-[chunkhash].chunk.js', - hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js', - hashFunction: 'sha256', - crossOriginLoading: 'anonymous', - path: output.path, - publicPath: output.publicPath, - }, - - optimization: { - runtimeChunk: { - name: 'common', - }, - splitChunks: { - cacheGroups: { - default: false, - vendors: false, - common: { - name: 'common', - chunks: 'all', - minChunks: 2, - minSize: 0, - test: /^(?!.*[\\/]node_modules[\\/]react-intl[\\/]).+$/, - }, - }, - }, - occurrenceOrder: true, - }, - - module: { - rules: Object.keys(rules).map(key => rules[key]), - strictExportPresence: true, - }, - - plugins: [ - new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))), - new webpack.NormalModuleReplacementPlugin( - /^history\//, (resource) => { - // temporary fix for https://github.com/ReactTraining/react-router/issues/5576 - // to reduce bundle size - resource.request = resource.request.replace(/^history/, 'history/es'); - }, - ), - new MiniCssExtractPlugin({ - filename: 'css/[name]-[contenthash:8].css', - chunkFilename: 'css/[name]-[contenthash:8].chunk.css', - }), - new AssetsManifestPlugin({ - integrity: true, - integrityHashes: ['sha256'], - entrypoints: true, - writeToDisk: true, - publicPath: true, - }), - new CircularDependencyPlugin({ - failOnError: true, - }) - ], - - resolve: { - extensions: settings.extensions, - modules: [ - resolve(settings.source_path), - 'node_modules', - ], - alias: { - "@": resolve(settings.source_path), - } - }, - - resolveLoader: { - modules: ['node_modules'], - }, - - node: { - // Called by http-link-header in an API we never use, increases - // bundle size unnecessarily - Buffer: false, - }, -}; diff --git a/postcss.config.js b/postcss.config.js index ddcbbbeeec..ba5abc2cd9 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,14 +1,13 @@ const postcssPresetEnv = require('postcss-preset-env'); /** @type {import('postcss-load-config').Config} */ -const config = ({ env }) => ({ +const config = () => ({ plugins: [ postcssPresetEnv({ features: { 'logical-properties-and-values': false } }), - env === 'production' ? require('cssnano') : '', ], }); diff --git a/vite.config.ts b/vite.config.ts index f7fe769e09..64ece6bcb4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,6 +13,17 @@ export default defineConfig({ emptyOutDir: true, manifest: 'manifest.json', rollupOptions: { + input: { + admin: path.resolve(__dirname, 'app/javascript/entrypoints/admin.tsx'), + application: path.resolve( + __dirname, + 'app/javascript/entrypoints/application.ts', + ), + twoFactor: path.resolve( + __dirname, + 'app/javascript/entrypoints/two_factor_authentication.ts', + ), + }, output: { chunkFileNames: (chunkInfo) => { if (