MM-46274 Add ability to run Boards as a product in development

This commit is contained in:
Harrison Healey 2022-08-17 16:13:35 -04:00
parent 765fbc88e9
commit d462d9a5d7
8 changed files with 2458 additions and 227 deletions

View file

@ -186,6 +186,9 @@ watch-plugin: modd-precheck ## Run and upload the plugin to a development server
live-watch-plugin: modd-precheck ## Run and update locally the plugin in the development server
cd mattermost-plugin; make live-watch
watch-product: ## Run the product as something the Mattermost web app will watch for
cd mattermost-plugin; make watch-product
mac-app: server-mac webapp ## Build Mac application.
rm -rf mac/temp
rm -rf mac/dist

View file

@ -84,7 +84,7 @@ ifneq ($(HAS_SERVER),)
endif
templates-archive: setup-go-work ## Build templates archive file
cd ../server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive"
cd ../server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive"
## Builds the server, if it exists, for all supported architectures.
.PHONY: server
@ -175,6 +175,10 @@ endif
deploy-from-watch: bundle
./build/bin/pluginctl deploy $(PLUGIN_ID) dist/$(BUNDLE_NAME)
.PHONE: watch-product
watch-product: apply
cd webapp && npm run start:product
## Setup dlv for attaching, identifying the plugin PID for other targets.
.PHONY: setup-attach
setup-attach:

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,8 @@
"test": "jest --forceExit --detectOpenHandles --verbose",
"test:watch": "jest --watch",
"test-ci": "jest --forceExit --detectOpenHandles --maxWorkers=2",
"check-types": "tsc"
"check-types": "tsc",
"start:product": "webpack serve --mode=development"
},
"devDependencies": {
"@babel/cli": "7.17.6",
@ -78,7 +79,8 @@
"ts-loader": "9.2.8",
"typescript": "4.6.2",
"webpack": "5.70.0",
"webpack-cli": "4.9.2"
"webpack-cli": "4.10.0",
"webpack-dev-server": "4.10.0"
},
"dependencies": {
"core-js": "3.21.1",

View file

@ -14,9 +14,8 @@ import {selectTeam} from 'mattermost-redux/actions/teams'
import {SuiteWindow} from '../../../webapp/src/types/index'
import {UserSettings} from '../../../webapp/src/userSettings'
const windowAny = (window as SuiteWindow)
windowAny.baseURL = '/plugins/focalboard'
windowAny.baseURL = process.env.TARGET_IS_PRODUCT ? '/plugins/boards' : '/plugins/focalboard'
windowAny.frontendBaseURL = '/boards'
windowAny.isFocalboardPlugin = true
@ -334,7 +333,7 @@ export default class Plugin {
const data = await octoClient.getMyTopBoards(timeRange, page, perPage, teamId)
return data
}
}
const data = await octoClient.getTeamTopBoards(timeRange, page, perPage, teamId)
@ -408,11 +407,3 @@ export default class Plugin {
this.registry?.unregisterWebSocketEventHandler(wsClient.clientPrefix + ACTION_UPDATE_BLOCK)
}
}
declare global {
interface Window {
registerPlugin(id: string, plugin: Plugin): void
}
}
window.registerPlugin(manifest.id, new Plugin())

View file

@ -0,0 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import manifest from './manifest'
import Plugin from './index'
declare global {
interface Window {
registerPlugin(id: string, plugin: Plugin): void
}
}
window.registerPlugin(manifest.id, new Plugin())

View file

@ -0,0 +1,4 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import('./index')

View file

@ -5,16 +5,21 @@ const exec = require('child_process').exec;
const path = require('path');
const webpack = require('webpack');
const {ModuleFederationPlugin} = require('webpack').container;
const tsTransformer = require('@formatjs/ts-transformer');
const PLUGIN_ID = require('../plugin.json').id;
const packageJson = require('./package.json');
const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
const TARGET_IS_PRODUCT = NPM_TARGET === 'start:product' || NPM_TARGET === 'build:product';
let mode = 'production';
let devtool;
const plugins = [];
if (NPM_TARGET === 'debug' || NPM_TARGET === 'debug:watch') {
if (NPM_TARGET === 'debug' || NPM_TARGET === 'debug:watch' || NPM_TARGET === 'start:product') {
mode = 'development';
devtool = 'source-map';
plugins.push(
@ -49,10 +54,8 @@ if (NPM_TARGET === 'build:watch' || NPM_TARGET === 'debug:watch' || NPM_TARGET =
});
}
module.exports = {
entry: [
'./src/index.tsx',
],
const config = {
entry: TARGET_IS_PRODUCT ? './src/remote_entry.ts' : './src/plugin_entry.ts',
resolve: {
modules: [
'src',
@ -61,7 +64,6 @@ module.exports = {
],
alias: {
moment: path.resolve(__dirname, '../../webapp/node_modules/moment/'),
'react-intl': path.resolve(__dirname, '../../webapp/node_modules/react-intl/'),
},
extensions: ['*', '.js', '.jsx', '.ts', '.tsx'],
},
@ -120,30 +122,80 @@ module.exports = {
},
],
},
externals: {
react: 'React',
redux: 'Redux',
'react-redux': 'ReactRedux',
'mm-react-router-dom': 'ReactRouterDom',
'prop-types': 'PropTypes',
'react-bootstrap': 'ReactBootstrap',
},
output: {
devtoolNamespace: PLUGIN_ID,
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'main.js',
},
devtool,
mode,
plugins,
};
if (TARGET_IS_PRODUCT) {
function makeSingletonSharedModules(packageNames) {
const sharedObject = {};
for (const packageName of packageNames) {
const version = packageJson.dependencies[packageName];
sharedObject[packageName] = {
requiredVersion: version,
singleton: true,
version,
};
}
return sharedObject;
}
config.plugins.push(new ModuleFederationPlugin({
name: PLUGIN_ID,
filename: 'remote_entry.js',
exposes: {
'.': './src/index',
// This probably won't need to be exposed in the long run, but its a POC for exposing multiple modules
'./manifest': './src/manifest',
},
shared: [
'@mattermost/client',
'prop-types',
makeSingletonSharedModules([
'react',
'react-dom',
'react-intl',
'react-redux',
'react-router-dom',
]),
],
}));
config.plugins.push(new webpack.DefinePlugin({
'process.env.TARGET_IS_PRODUCT': TARGET_IS_PRODUCT, // TODO We might want a better name for this
}));
} else {
config.resolve.alias['react-intl'] = path.resolve(__dirname, '../../webapp/node_modules/react-intl/');
config.outputs = {
devtoolNamespace: PLUGIN_ID,
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'main.js',
};
}
const env = {};
env.RUDDER_KEY = JSON.stringify(process.env.RUDDER_KEY || ''); //eslint-disable-line no-process-env
env.RUDDER_DATAPLANE_URL = JSON.stringify(process.env.RUDDER_DATAPLANE_URL || ''); //eslint-disable-line no-process-env
module.exports.plugins.push(new webpack.DefinePlugin({
config.plugins.push(new webpack.DefinePlugin({
'process.env': env,
}));
if (NPM_TARGET === 'start:product') {
config.devServer = {
port: 9006,
devMiddleware: {
writeToDisk: false,
},
};
}
module.exports = config;