From 4cbf6e93d24133a982761b889b3635fb1691f9cf Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 15 May 2023 16:18:10 -0400 Subject: [PATCH] Remove Webpack dev servers for Boards/Playbooks (#23378) * Add option to run web app build without dev servers * Completely remove product dev servers * Update unit test * Fix another test --- server/channels/web/handlers.go | 20 -------- server/channels/web/handlers_test.go | 4 +- webapp/boards/package.json | 4 +- webapp/boards/webpack.config.js | 32 ------------- webapp/channels/webpack.config.js | 68 ++++++++++++---------------- webapp/playbooks/package.json | 4 +- webapp/playbooks/webpack.config.js | 27 ----------- 7 files changed, 32 insertions(+), 127 deletions(-) diff --git a/server/channels/web/handlers.go b/server/channels/web/handlers.go index 802f5eb81c..d9b20fe9c9 100644 --- a/server/channels/web/handlers.go +++ b/server/channels/web/handlers.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "net/http" - "os" "reflect" "runtime" "strconv" @@ -132,25 +131,6 @@ func generateDevCSP(c Context) string { } } - // Add flags for Webpack dev servers used by other products during development - if model.BuildNumber == "dev" { - boardsURL := os.Getenv("MM_BOARDS_DEV_SERVER_URL") - if boardsURL == "" { - // Focalboard runs on http://localhost:9006 by default - boardsURL = "http://localhost:9006" - } - - devCSP = append(devCSP, boardsURL) - - playbooksURL := os.Getenv("MM_PLAYBOOKS_DEV_SERVER_URL") - if playbooksURL == "" { - // Playbooks runs on http://localhost:9007 by default - playbooksURL = "http://localhost:9007" - } - - devCSP = append(devCSP, playbooksURL) - } - if len(devCSP) == 0 { return "" } diff --git a/server/channels/web/handlers_test.go b/server/channels/web/handlers_test.go index 3c0c9c4200..924262068e 100644 --- a/server/channels/web/handlers_test.go +++ b/server/channels/web/handlers_test.go @@ -449,7 +449,7 @@ func TestHandlerServeCSPHeader(t *testing.T) { response := httptest.NewRecorder() handler.ServeHTTP(response, request) assert.Equal(t, 200, response.Code) - assert.Equal(t, []string{"frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3 'unsafe-eval' 'unsafe-inline' http://localhost:9006 http://localhost:9007"}, response.Header()["Content-Security-Policy"]) + assert.Equal(t, []string{"frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com js.stripe.com/v3 'unsafe-eval' 'unsafe-inline'"}, response.Header()["Content-Security-Policy"]) }) } @@ -472,7 +472,7 @@ func TestGenerateDevCSP(t *testing.T) { devCSP := generateDevCSP(*c) - assert.Equal(t, " 'unsafe-eval' 'unsafe-inline' http://localhost:9006 http://localhost:9007", devCSP) + assert.Equal(t, " 'unsafe-eval' 'unsafe-inline'", devCSP) }) t.Run("allowed dev flags", func(t *testing.T) { diff --git a/webapp/boards/package.json b/webapp/boards/package.json index 4d771ccc8e..38c01516a9 100644 --- a/webapp/boards/package.json +++ b/webapp/boards/package.json @@ -6,9 +6,7 @@ "scripts": { "build": "webpack --mode=production", "build:watch": "webpack --mode=production --watch", - "start:product": "webpack serve --mode=development", - "debug": "webpack --mode=none", - "debug:watch": "webpack --mode=development --watch", + "start:product": "webpack --mode=development --watch", "check-lint": "eslint --ignore-pattern ../.git-ignore --ignore-pattern dist --ext js,jsx,tsx,ts . --quiet --cache", "check-lint:fix": "npm run check-lint -- --fix", "check-style": "stylelint **/*.scss", diff --git a/webapp/boards/webpack.config.js b/webapp/boards/webpack.config.js index c8d540314b..f870adc80d 100644 --- a/webapp/boards/webpack.config.js +++ b/webapp/boards/webpack.config.js @@ -186,36 +186,4 @@ config.plugins.push(new MiniCssExtractPlugin({ chunkFilename: '[name].[contenthash].css', })); -if (NPM_TARGET === 'start:product') { - const url = new URL(process.env.MM_BOARDS_DEV_SERVER_URL ?? 'http://localhost:9006'); - - const protocol = url.protocol.substring(0, url.protocol.length - 1); - const hostname = url.hostname; - let port = url.port; - if (!port) { - port = protocol === 'https' ? '443' : '80'; - } - - config.devServer = { - server: { - type: protocol, - options: { - minVersion: process.env.MM_SERVICESETTINGS_TLSMINVER ?? 'TLSv1.2', - key: process.env.MM_SERVICESETTINGS_TLSKEYFILE, - cert: process.env.MM_SERVICESETTINGS_TLSCERTFILE, - }, - }, - host: hostname, - port, - devMiddleware: { - writeToDisk: false, - }, - static: { - directory: path.join(__dirname, 'static'), - publicPath: '/static', - }, - }; -} -/* eslint-enable no-process-env */ - module.exports = config; diff --git a/webapp/channels/webpack.config.js b/webapp/channels/webpack.config.js index 51bbe8c3fb..16c018ccd1 100644 --- a/webapp/channels/webpack.config.js +++ b/webapp/channels/webpack.config.js @@ -3,6 +3,7 @@ /* eslint-disable no-console, no-process-env */ +const fs = require('fs'); const path = require('path'); const url = require('url'); @@ -29,9 +30,6 @@ const targetIsEslint = NPM_TARGET === 'check' || NPM_TARGET === 'fix' || process const DEV = targetIsRun || targetIsStats || targetIsDevServer; -const boardsDevServerUrl = process.env.MM_BOARDS_DEV_SERVER_URL ?? 'http://localhost:9006'; -const playbooksDevServerUrl = process.env.MM_PLAYBOOKS_DEV_SERVER_URL ?? 'http://localhost:9007'; - const STANDARD_EXCLUDE = [ /node_modules/, ]; @@ -280,16 +278,34 @@ var config = { ], }; +if (DEV) { + config.plugins.push({ + apply: (compiler) => { + compiler.hooks.afterEmit.tap('AfterEmitPlugin', () => { + const boardsDist = path.resolve(__dirname, '../boards/dist'); + const boardsSymlink = './dist/products/boards'; + const playbooksDist = path.resolve(__dirname, '../playbooks/dist'); + const playbooksSymlink = './dist/products/playbooks'; + + fs.mkdir('./dist/products', () => { + if (!fs.existsSync(boardsSymlink)) { + fs.symlinkSync(boardsDist, boardsSymlink, 'dir'); + } + if (!fs.existsSync(playbooksSymlink)) { + fs.symlinkSync(playbooksDist, playbooksSymlink, 'dir'); + } + }); + }); + }, + }); +} + function generateCSP() { let csp = 'script-src \'self\' cdn.rudderlabs.com/ js.stripe.com/v3'; if (DEV) { // react-hot-loader and development source maps require eval csp += ' \'unsafe-eval\''; - - csp += ' ' + boardsDevServerUrl; - - csp += ' ' + playbooksDevServerUrl; } return csp; @@ -321,42 +337,19 @@ async function initializeModuleFederation() { async function getRemoteContainers() { const products = [ - {name: 'boards', baseUrl: boardsDevServerUrl}, - {name: 'playbooks', baseUrl: playbooksDevServerUrl}, + {name: 'boards'}, + {name: 'playbooks'}, ]; const remotes = {}; - - if (process.env.MM_DONT_INCLUDE_PRODUCTS) { - console.warn('Skipping initialization of products'); - } else if (DEV) { - // For development, we use Webpack dev servers for each product - for (const product of products) { - remotes[product.name] = `${product.name}@${product.baseUrl}/remote_entry.js`; - } - } else { - // For production, hardcode the URLs of product containers to be based on the web app URL - for (const product of products) { - remotes[product.name] = `${product.name}@[window.basename]/static/products/${product.name}/remote_entry.js?bt=${buildTimestamp}`; - } - } - - const aliases = {}; - for (const product of products) { - if (remotes[product.name]) { - continue; - } - - // Add false aliases to prevent Webpack from trying to resolve the missing modules - aliases[product.name] = false; - aliases[`${product.name}/manifest`] = false; + remotes[product.name] = `${product.name}@[window.basename]/static/products/${product.name}/remote_entry.js?bt=${buildTimestamp}`; } - return {remotes, aliases}; + return {remotes}; } - const {remotes, aliases} = await getRemoteContainers(); + const {remotes} = await getRemoteContainers(); const moduleFederationPluginOptions = { name: 'mattermost_webapp', @@ -404,11 +397,6 @@ async function initializeModuleFederation() { // Add this plugin to perform the substitution of window.basename when loading remote containers config.plugins.push(new ExternalTemplateRemotesPlugin()); - config.resolve.alias = { - ...config.resolve.alias, - ...aliases, - }; - config.plugins.push(new webpack.DefinePlugin({ REMOTE_CONTAINERS: JSON.stringify(remotes), })); diff --git a/webapp/playbooks/package.json b/webapp/playbooks/package.json index f69480c797..b8d7083a26 100644 --- a/webapp/playbooks/package.json +++ b/webapp/playbooks/package.json @@ -108,7 +108,6 @@ "build:watch": "webpack --mode=production --watch", "debug": "webpack --mode=development", "debug:watch": "webpack --mode=development --watch", - "dev-server": "webpack serve --mode=development", "check": "eslint --ignore-pattern node_modules --ignore-pattern dist --ext .js --ext .jsx --ext tsx --ext ts . --quiet --cache", "fix": "eslint --ignore-pattern node_modules --ignore-pattern dist --ext .js --ext .jsx --ext tsx --ext ts . --quiet --fix --cache", "test": "cross-env TZ=Etc/UTC jest", @@ -120,8 +119,7 @@ "i18n-extract": "formatjs extract \"src/**/*.{ts,tsx}\" --ignore \"**/*.d.ts\" --id-interpolation-pattern '[sha512:contenthash:base64:6]' --format simple --out-file i18n/en.json", "graphql": "graphql-codegen --config graphql_gen.ts", "report-unused-exports": "ts-prune", - "build:product": "webpack --mode=production", - "start:product": "webpack serve --mode=development", + "start:product": "webpack --mode=development --watch", "deploy:product": "node scripts/deploy.js", "clean": "rm -rf node_modules" } diff --git a/webapp/playbooks/webpack.config.js b/webapp/playbooks/webpack.config.js index 31737058d9..9ea491e2bf 100644 --- a/webapp/playbooks/webpack.config.js +++ b/webapp/playbooks/webpack.config.js @@ -133,31 +133,4 @@ config.output = { chunkFilename: '[name].[contenthash].js', }; -if (NPM_TARGET === 'start:product') { - const url = new URL(process.env.MM_PLAYBOOKS_DEV_SERVER_URL ?? 'http://localhost:9007'); - - const protocol = url.protocol.substring(0, url.protocol.length - 1); - const hostname = url.hostname; - let port = url.port; - if (!port) { - port = protocol === 'https' ? '443' : '80'; - } - - config.devServer = { - server: { - type: protocol, - options: { - minVersion: process.env.MM_SERVICESETTINGS_TLSMINVER ?? 'TLSv1.2', - key: process.env.MM_SERVICESETTINGS_TLSKEYFILE, - cert: process.env.MM_SERVICESETTINGS_TLSCERTFILE, - }, - }, - host: hostname, - port, - devMiddleware: { - writeToDisk: false, - }, - }; -} - module.exports = config;