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
Этот коммит содержится в:
Harrison Healey
2023-05-15 16:18:10 -04:00
коммит произвёл GitHub
родитель e1a2443f1a
Коммит 4cbf6e93d2
7 изменённых файлов: 32 добавлений и 127 удалений

Просмотреть файл

@@ -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 ""
}

Просмотреть файл

@@ -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) {

Просмотреть файл

@@ -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",

Просмотреть файл

@@ -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;

Просмотреть файл

@@ -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),
}));

Просмотреть файл

@@ -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"
}

Просмотреть файл

@@ -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;