diff --git a/lib/webpack/shared.cjs b/lib/webpack/shared.cjs index cde1e0a6d..f31e32f8f 100644 --- a/lib/webpack/shared.cjs +++ b/lib/webpack/shared.cjs @@ -1,299 +1,301 @@ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const TerserPlugin = require('terser-webpack-plugin'); const webpack = require('webpack'); async function getConfig(configName) { const { getCommConfig } = await import( // eslint-disable-next-line monorepo/no-relative-import '../../keyserver/dist/lib/utils/comm-config.js' ); return await getCommConfig(configName); } const sharedPlugins = [ new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1, }), ]; const cssLoader = { loader: 'css-loader', options: { modules: { mode: 'local', localIdentName: '[path][name]__[local]--[contenthash:base64:5]', }, }, }; const cssExtractLoader = { loader: MiniCssExtractPlugin.loader, }; const styleLoader = { loader: 'style-loader', }; function getBabelRule(babelConfig) { return { test: /\.js$/, exclude: /node_modules\/(?!lib)/, loader: 'babel-loader', options: babelConfig, }; } function getBrowserBabelRule(babelConfig) { const babelRule = getBabelRule(babelConfig); return { ...babelRule, options: { ...babelRule.options, presets: [ ...babelRule.options.presets, [ '@babel/preset-env', { targets: 'defaults', useBuiltIns: 'usage', corejs: '3.6', }, ], ], }, }; } const imageRule = { test: /\.(png|svg)$/, type: 'asset/inline', }; const typographyRule = { test: /\.(woff2|woff)$/, type: 'asset/inline', }; function createBaseBrowserConfig(baseConfig) { return { ...baseConfig, name: 'browser', optimization: { minimizer: [new TerserPlugin(), new CssMinimizerPlugin()], }, plugins: [ ...(baseConfig.plugins ?? []), ...sharedPlugins, new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], }), new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: [], }), ], node: { global: true, }, }; } async function getConfigs() { const [alchemySecret, walletConnectSecret] = await Promise.all([ getConfig({ folder: 'secrets', name: 'alchemy' }), getConfig({ folder: 'secrets', name: 'walletconnect' }), ]); const alchemyKey = alchemySecret?.key; const walletConnectKey = walletConnectSecret?.key; return { alchemyKey, walletConnectKey }; } -async function createProdBrowserConfig(baseConfig, babelConfig) { +async function createProdBrowserConfig(baseConfig, babelConfig, envVars) { const browserConfig = createBaseBrowserConfig(baseConfig); const babelRule = getBrowserBabelRule(babelConfig); const { alchemyKey, walletConnectKey } = await getConfigs(); return { ...browserConfig, mode: 'production', plugins: [ ...browserConfig.plugins, new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production'), BROWSER: true, COMM_ALCHEMY_KEY: JSON.stringify(alchemyKey), COMM_WALLETCONNECT_KEY: JSON.stringify(walletConnectKey), + ...envVars, }, }), new MiniCssExtractPlugin({ filename: 'prod.[contenthash:12].build.css', }), ], module: { rules: [ { ...babelRule, options: { ...babelRule.options, plugins: [ ...babelRule.options.plugins, '@babel/plugin-transform-react-constant-elements', ['transform-remove-console', { exclude: ['error', 'warn'] }], ], }, }, { test: /\.css$/, exclude: /node_modules\/.*\.css$/, use: [ cssExtractLoader, { ...cssLoader, options: { ...cssLoader.options, url: false, }, }, ], }, { test: /node_modules\/.*\.css$/, sideEffects: true, use: [ cssExtractLoader, { ...cssLoader, options: { ...cssLoader.options, url: false, modules: false, }, }, ], }, ], }, }; } -async function createDevBrowserConfig(baseConfig, babelConfig) { +async function createDevBrowserConfig(baseConfig, babelConfig, envVars) { const browserConfig = createBaseBrowserConfig(baseConfig); const babelRule = getBrowserBabelRule(babelConfig); const { alchemyKey, walletConnectKey } = await getConfigs(); return { ...browserConfig, mode: 'development', plugins: [ ...browserConfig.plugins, new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('development'), BROWSER: true, COMM_ALCHEMY_KEY: JSON.stringify(alchemyKey), COMM_WALLETCONNECT_KEY: JSON.stringify(walletConnectKey), + ...envVars, }, }), new ReactRefreshWebpackPlugin(), ], module: { rules: [ { ...babelRule, options: { ...babelRule.options, plugins: [ require.resolve('react-refresh/babel'), ...babelRule.options.plugins, ], }, }, imageRule, typographyRule, { test: /\.css$/, exclude: /node_modules\/.*\.css$/, use: [styleLoader, cssLoader], }, { test: /node_modules\/.*\.css$/, sideEffects: true, use: [ styleLoader, { ...cssLoader, options: { ...cssLoader.options, modules: false, }, }, ], }, ], }, devtool: 'eval-cheap-module-source-map', }; } async function createNodeServerRenderingConfig(baseConfig, babelConfig) { const { alchemyKey, walletConnectKey } = await getConfigs(); return { ...baseConfig, name: 'server', target: 'node', module: { rules: [ getBabelRule(babelConfig), { test: /\.css$/, use: { ...cssLoader, options: { ...cssLoader.options, modules: { ...cssLoader.options.modules, exportOnlyLocals: true, }, }, }, }, ], }, plugins: [ ...sharedPlugins, new webpack.DefinePlugin({ 'process.env': { COMM_ALCHEMY_KEY: JSON.stringify(alchemyKey), COMM_WALLETCONNECT_KEY: JSON.stringify(walletConnectKey), }, }), ], }; } function createWebWorkersConfig(env, baseConfig, babelConfig) { return { ...baseConfig, name: 'webworkers', target: 'webworker', mode: env.prod ? 'production' : 'development', module: { rules: [getBrowserBabelRule(babelConfig)], }, plugins: [ ...sharedPlugins, ...baseConfig.plugins, new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(env.prod ? 'production' : 'development'), BROWSER: true, }, }), ], }; } module.exports = { createProdBrowserConfig, createDevBrowserConfig, createNodeServerRenderingConfig, createWebWorkersConfig, }; diff --git a/web/webpack.config.cjs b/web/webpack.config.cjs index 303c22152..d3da405fd 100644 --- a/web/webpack.config.cjs +++ b/web/webpack.config.cjs @@ -1,189 +1,204 @@ const CopyPlugin = require('copy-webpack-plugin'); const path = require('path'); const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); const { createProdBrowserConfig, createDevBrowserConfig, createNodeServerRenderingConfig, createWebWorkersConfig, } = require('lib/webpack/shared.cjs'); const babelConfig = require('./babel.config.cjs'); +async function getConfig(configName) { + const { getCommConfig } = await import( + // eslint-disable-next-line monorepo/no-relative-import + '../keyserver/dist/lib/utils/comm-config.js' + ); + return await getCommConfig(configName); +} + const baseBrowserConfig = { entry: { browser: ['./script.js'], }, output: { filename: 'prod.[contenthash:12].build.js', path: path.join(__dirname, 'dist'), }, resolve: { alias: { '../images': path.resolve('../keyserver/images'), }, fallback: { crypto: false, fs: false, path: false, }, }, }; const baseDevBrowserConfig = { ...baseBrowserConfig, output: { ...baseBrowserConfig.output, filename: 'dev.build.js', pathinfo: true, publicPath: 'http://localhost:8080/', }, devServer: { port: 8080, headers: { 'Access-Control-Allow-Origin': '*' }, allowedHosts: ['all'], host: '0.0.0.0', static: { directory: path.join(__dirname, 'dist'), }, }, plugins: [ new CopyPlugin({ patterns: [ { from: 'node_modules/@commapp/olm/olm.wasm', to: path.join(__dirname, 'dist'), }, ], }), new CopyPlugin({ patterns: [ { from: 'node_modules/@commapp/opaque-ke-wasm' + '/pkg/comm_opaque2_wasm_bg.wasm', to: path.join(__dirname, 'dist', 'opaque-ke.wasm'), }, ], }), ], }; const baseProdBrowserConfig = { ...baseBrowserConfig, plugins: [ new CopyPlugin({ patterns: [ { from: 'node_modules/@commapp/olm/olm.wasm', to: path.join(__dirname, 'dist', 'olm.[contenthash:12].wasm'), }, ], }), new CopyPlugin({ patterns: [ { from: 'node_modules/@commapp/opaque-ke-wasm' + '/pkg/comm_opaque2_wasm_bg.wasm', to: path.join(__dirname, 'dist', 'opaque-ke.[contenthash:12].wasm'), }, ], }), new WebpackManifestPlugin({ publicPath: '', }), ], }; const baseNodeServerRenderingConfig = { externals: ['react', 'react-dom', 'react-redux'], entry: { keyserver: ['./loading.react.js'], }, output: { filename: 'app.build.cjs', library: 'app', libraryTarget: 'commonjs2', path: path.join(__dirname, 'dist'), }, }; const baseWebWorkersConfig = { entry: { pushNotif: './push-notif/service-worker.js', database: './database/worker/db-worker.js', }, output: { filename: '[name].build.js', path: path.join(__dirname, 'dist', 'webworkers'), }, resolve: { fallback: { crypto: false, fs: false, path: false, }, }, }; const devWebWorkersPlugins = [ new CopyPlugin({ patterns: [ { from: 'node_modules/sql.js/dist/sql-wasm.wasm', to: path.join(__dirname, 'dist', 'webworkers'), }, ], }), ]; const prodWebWorkersPlugins = [ new CopyPlugin({ patterns: [ { from: 'node_modules/sql.js/dist/sql-wasm.wasm', to: path.join( __dirname, 'dist', 'webworkers', 'sql-wasm.[contenthash:12].wasm', ), }, ], }), new WebpackManifestPlugin({ publicPath: '', }), ]; module.exports = async function (env) { + const identityServiceConfig = await getConfig({ + folder: 'secrets', + name: 'identity_service_config', + }); + const envVars = { + IDENTITY_SERVICE_CONFIG: JSON.stringify(identityServiceConfig), + }; const browserConfigPromise = env.prod - ? createProdBrowserConfig(baseProdBrowserConfig, babelConfig) - : createDevBrowserConfig(baseDevBrowserConfig, babelConfig); + ? createProdBrowserConfig(baseProdBrowserConfig, babelConfig, envVars) + : createDevBrowserConfig(baseDevBrowserConfig, babelConfig, envVars); const nodeConfigPromise = createNodeServerRenderingConfig( baseNodeServerRenderingConfig, babelConfig, ); const [browserConfig, nodeConfig] = await Promise.all([ browserConfigPromise, nodeConfigPromise, ]); const nodeServerRenderingConfig = { ...nodeConfig, mode: env.prod ? 'production' : 'development', }; const workersConfig = { ...baseWebWorkersConfig, plugins: env.prod ? prodWebWorkersPlugins : devWebWorkersPlugins, }; const webWorkersConfig = createWebWorkersConfig( env, workersConfig, babelConfig, ); return [browserConfig, nodeServerRenderingConfig, webWorkersConfig]; };