2025-02-25 06:52:50 +00:00
|
|
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
2021-09-08 18:24:58 +00:00
|
|
|
const webpack = require('webpack');
|
2021-03-31 14:01:01 +00:00
|
|
|
const path = require('path');
|
2022-08-16 07:06:47 +00:00
|
|
|
const CompressionPlugin = require('compression-webpack-plugin');
|
|
|
|
|
const TerserPlugin = require('terser-webpack-plugin');
|
2023-03-24 11:35:08 +00:00
|
|
|
require('dotenv').config({ path: '../.env' });
|
2023-03-20 11:34:24 +00:00
|
|
|
const hash = require('string-hash');
|
2023-09-04 04:30:14 +00:00
|
|
|
const { sentryWebpackPlugin } = require('@sentry/webpack-plugin');
|
|
|
|
|
const fs = require('fs');
|
|
|
|
|
const versionPath = path.resolve(__dirname, '.version');
|
|
|
|
|
const version = fs.readFileSync(versionPath, 'utf-8').trim();
|
2025-08-03 07:09:18 +00:00
|
|
|
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
2021-03-31 14:01:01 +00:00
|
|
|
|
|
|
|
|
const environment = process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
2025-02-25 12:28:43 +00:00
|
|
|
const edition = process.env.TOOLJET_EDITION;
|
2025-08-03 07:09:18 +00:00
|
|
|
const isDevEnv = process.env.NODE_ENV === 'development';
|
2025-02-25 06:52:50 +00:00
|
|
|
|
|
|
|
|
// Create path to empty module
|
|
|
|
|
const emptyModulePath = path.resolve(__dirname, 'src/modules/emptyModule');
|
2021-03-31 14:01:01 +00:00
|
|
|
|
|
|
|
|
const API_URL = {
|
2022-08-27 16:28:24 +00:00
|
|
|
production: process.env.TOOLJET_SERVER_URL || (process.env.SERVE_CLIENT !== 'false' ? '__REPLACE_SUB_PATH__' : ''),
|
2022-03-16 16:06:28 +00:00
|
|
|
development: `http://localhost:${process.env.TOOLJET_SERVER_PORT || 3000}`,
|
2021-04-30 08:10:57 +00:00
|
|
|
};
|
2021-03-31 14:01:01 +00:00
|
|
|
|
2022-08-27 16:28:24 +00:00
|
|
|
const ASSET_PATH = process.env.ASSET_PATH || '';
|
2022-03-01 07:55:51 +00:00
|
|
|
|
2022-08-29 10:19:39 +00:00
|
|
|
function stripTrailingSlash(str) {
|
|
|
|
|
return str.replace(/[/]+$/, '');
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-22 11:22:34 +00:00
|
|
|
const plugins = [
|
2025-02-25 06:52:50 +00:00
|
|
|
new webpack.ProvidePlugin({
|
|
|
|
|
process: 'process/browser.js',
|
|
|
|
|
Buffer: ['buffer', 'Buffer'],
|
|
|
|
|
}),
|
2024-02-22 11:22:34 +00:00
|
|
|
new HtmlWebpackPlugin({
|
|
|
|
|
template: './src/index.ejs',
|
|
|
|
|
favicon: './assets/images/logo.svg',
|
|
|
|
|
}),
|
|
|
|
|
new CompressionPlugin({
|
|
|
|
|
test: /\.js(\?.*)?$/i,
|
|
|
|
|
algorithm: 'gzip',
|
|
|
|
|
}),
|
|
|
|
|
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /(en)$/),
|
|
|
|
|
new webpack.DefinePlugin({
|
|
|
|
|
'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
|
|
|
|
|
'process.env.SERVE_CLIENT': JSON.stringify(process.env.SERVE_CLIENT),
|
2025-02-25 12:28:43 +00:00
|
|
|
'process.env.TOOLJET_EDITION': JSON.stringify(edition || 'ce'),
|
2025-02-25 06:52:50 +00:00
|
|
|
}),
|
|
|
|
|
// Module replacement for restricted imports
|
|
|
|
|
new webpack.NormalModuleReplacementPlugin(/^(@ee\/|@cloud\/)/, (resource) => {
|
2025-02-25 12:28:43 +00:00
|
|
|
const edition = process.env.TOOLJET_EDITION || 'ce';
|
2025-02-25 06:52:50 +00:00
|
|
|
|
|
|
|
|
// Only replace if the current edition shouldn't have access
|
|
|
|
|
if (edition === 'ce' && resource.request.startsWith('@ee/')) {
|
|
|
|
|
resource.request = emptyModulePath;
|
|
|
|
|
} else if (['ce', 'ee'].includes(edition) && resource.request.startsWith('@cloud/')) {
|
|
|
|
|
resource.request = emptyModulePath;
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, leave the original import intact
|
2024-02-22 11:22:34 +00:00
|
|
|
}),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (process.env.APM_VENDOR === 'sentry') {
|
|
|
|
|
plugins.push(
|
|
|
|
|
// Add Sentry plugin for error and performance monitoring
|
|
|
|
|
sentryWebpackPlugin({
|
|
|
|
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
|
|
|
org: process.env.SENTRY_ORG,
|
|
|
|
|
project: process.env.SENTRY_PROJECT,
|
|
|
|
|
release: {
|
|
|
|
|
// The version should be same as what its when we are sending error events
|
|
|
|
|
name: `tooljet-${version}`,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-03 07:09:18 +00:00
|
|
|
if (isDevEnv) {
|
|
|
|
|
plugins.push(new ReactRefreshWebpackPlugin({ overlay: false }));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 14:01:01 +00:00
|
|
|
module.exports = {
|
2022-01-17 07:08:17 +00:00
|
|
|
mode: environment,
|
|
|
|
|
optimization: {
|
2022-08-16 07:06:47 +00:00
|
|
|
minimize: environment === 'production',
|
2022-01-17 07:08:17 +00:00
|
|
|
usedExports: true,
|
2022-08-16 07:06:47 +00:00
|
|
|
runtimeChunk: 'single',
|
2026-01-23 10:11:49 +00:00
|
|
|
moduleIds: 'deterministic',
|
|
|
|
|
chunkIds: 'deterministic',
|
|
|
|
|
realContentHash: true,
|
2022-08-16 07:06:47 +00:00
|
|
|
minimizer: [
|
|
|
|
|
new TerserPlugin({
|
|
|
|
|
terserOptions: {
|
2025-02-25 06:52:50 +00:00
|
|
|
keep_classnames: true,
|
|
|
|
|
keep_fnames: true,
|
|
|
|
|
compress: {
|
|
|
|
|
drop_debugger: true,
|
|
|
|
|
drop_console: true,
|
|
|
|
|
},
|
2022-08-16 07:06:47 +00:00
|
|
|
},
|
|
|
|
|
parallel: environment === 'production',
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
splitChunks: {
|
|
|
|
|
cacheGroups: {
|
|
|
|
|
vendors: {
|
|
|
|
|
test: /[\\/]node_modules[\\/]/,
|
|
|
|
|
name: 'vendor',
|
|
|
|
|
chunks: 'all',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-01-17 07:08:17 +00:00
|
|
|
},
|
2021-10-02 05:52:02 +00:00
|
|
|
target: 'web',
|
2021-04-30 08:10:57 +00:00
|
|
|
resolve: {
|
2023-01-05 05:58:15 +00:00
|
|
|
extensions: ['.js', '.jsx', '.png', '.wasm', '.tar', '.data', '.svg', '.png', '.jpg', '.jpeg', '.gif', '.json'],
|
2021-09-21 13:48:28 +00:00
|
|
|
alias: {
|
|
|
|
|
'@': path.resolve(__dirname, 'src/'),
|
2021-11-17 11:21:50 +00:00
|
|
|
'@ee': path.resolve(__dirname, 'ee/'),
|
2025-02-25 06:52:50 +00:00
|
|
|
'@cloud': path.resolve(__dirname, 'cloud/'),
|
2023-01-04 10:03:55 +00:00
|
|
|
'@assets': path.resolve(__dirname, 'assets/'),
|
2025-02-25 06:52:50 +00:00
|
|
|
'@white-label': path.resolve(__dirname, 'src/_helpers/white-label'),
|
|
|
|
|
},
|
|
|
|
|
fallback: {
|
|
|
|
|
process: require.resolve('process/browser.js'),
|
|
|
|
|
path: require.resolve('path-browserify'),
|
2026-01-23 10:11:49 +00:00
|
|
|
util: require.resolve('util/'),
|
2025-02-25 06:52:50 +00:00
|
|
|
'@ee/modules': emptyModulePath,
|
|
|
|
|
'@cloud/modules': emptyModulePath,
|
2021-09-21 13:48:28 +00:00
|
|
|
},
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
2025-02-25 06:52:50 +00:00
|
|
|
devtool: environment === 'development' ? 'eval-source-map' : 'hidden-source-map',
|
2021-04-30 08:10:57 +00:00
|
|
|
module: {
|
|
|
|
|
rules: [
|
|
|
|
|
{
|
|
|
|
|
test: /\.ttf$/,
|
2021-09-08 18:24:58 +00:00
|
|
|
use: ['file-loader'],
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
2022-10-27 08:41:26 +00:00
|
|
|
{
|
|
|
|
|
test: /\.wasm$/,
|
|
|
|
|
use: ['file-loader'],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
test: /\.tar$/,
|
|
|
|
|
use: ['file-loader'],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
test: /\.data$/,
|
|
|
|
|
use: ['file-loader'],
|
|
|
|
|
},
|
2021-08-25 15:14:55 +00:00
|
|
|
{
|
|
|
|
|
test: /\.svg$/,
|
2023-03-20 11:34:24 +00:00
|
|
|
use: ({ resource }) => ({
|
|
|
|
|
loader: '@svgr/webpack',
|
|
|
|
|
options: {
|
|
|
|
|
svgoConfig: {
|
|
|
|
|
plugins: [
|
|
|
|
|
{
|
|
|
|
|
name: 'prefixIds',
|
|
|
|
|
cleanupIDs: {
|
|
|
|
|
prefix: `svg-${hash(resource)}`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
2021-08-25 15:14:55 +00:00
|
|
|
},
|
|
|
|
|
},
|
2023-03-20 11:34:24 +00:00
|
|
|
}),
|
2021-08-25 15:14:55 +00:00
|
|
|
},
|
2021-04-30 08:10:57 +00:00
|
|
|
{
|
|
|
|
|
test: /\.css$/,
|
2021-10-02 05:52:02 +00:00
|
|
|
use: [
|
|
|
|
|
{
|
|
|
|
|
loader: 'style-loader',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
loader: 'css-loader',
|
Feature: Collaboration ( realtime comments for canvas ) 🔥 (#810)
* feat: initial commit for collaboration feature
* add dnd to comments
* add positions endpoint
* feat: encapsulate all http common logic in http-client
* segregate sections and transfer responsibility of state
* feat: use-spring to add fade effect :zap:
* fix: open in right
* fix: left-right position css
* add footer for message
* integrate getcomment endpoint
* use fromnow for date ago
* add dnd
* - Add data trasfer object for comment
- Add class-validator package to check the response type from client
- Add comment repository class for persistance layer
- Add comment service with std. http methods
- Update controller with all http methods
- Update comment module
- Fix http-client bug when error is thrown
* fix http client bug when error is thrown
* feat: add entity thread
* feat: add migrations for thread and comment
* update entitites
* add tid to migration
* filter comments by tid(thread_id)
* fix: comment migration, add missing column comment
* feat: integrate in ui
* feat: split comments based on app_id
* fix: dnd to correct position
* package json engines
* engines update
* update npm
* npm 6 to 7
* fix: add user initials to thread
* fix: add firtname lastname to the comments
* - Return user object when save thread called
- Hide password field from user response
- Fix created_at date typo
- Instead of fetch all threads on new thread added, add the response to array of existing threads
* feat: update ui components
* change icon on comments view
* ui fixes
* fix: close icon close the popover
* temp: comment select: false
* use currentUser from localStorage
* fix: on click outside if comment is open, dont hit addThread
* fix: auth token issue in http-client
* on drag hide the comment if open
* add jwt auth
* spec: add test for comment & thread
* cleanup: remove console.log
* feat: add comment actions
* feat: add edit, delete, resolve options
* feat: add mentions component
* feat: add nestjs websockets
* temp
* websocket: establish client-server communication
* ws: add message listner to comments module in ui
* feat: add broadcast method to broadcast new events to all clients :bomb:
* ws: cleanup :call_me_hand:
* fix: remove max height from comment actions
* feat: add user mentions, emoji support
* fix: add static list of users - temp
* update and delete iterations
* - Rename comment, thread to comments, threads
- Add conditional actions
- Show edit, delete only if he is comment owner
- Show resolve only if he is thread owner
* reset engines
* move svgr webpack to deps
* fix: ui issues
* remove log stmt
* refactor: move resolved icon to comment-header
* feat: allow comments to be added on top of widgets
* feat: add keyboard shortcut
* scroll to bottom on comment add
* ui fixes
* feat: add react toast for notification display
* feat: add comment badge
* fix: ws connection
* fix: ws
* remove rvrse
* feat: add comment sidebar
* feat: add comment right sidebar
* fix: add missing foreign key elements
* - upgrade typeorm to 0.2.38
- comment sidebar ui
- added filter ui
* feat: on click of right sidebar notificaiton open the comment box
* reset engines
* fix: add organization id to the comment and thread module
* fix: add current version id
* add currentversion id
* disable comments if no id present
* temp:checking for heroku deploy
* fetch app on edit and deploy version
* rename current_version_id to app_versions_id
* ui fixes
* show mentioned user in blue color
* add ui changes
* add authorization for create thread
* change color to blue on click of comment, add auth for other endpoints of thread
* update threads, notifications using socket
* add auth for comments
* remove events spec file
* fix duplicate key error
* fix notificaitons updation on edit, delete, resolve buttons clicked
* update notifications for edit
* feature toggle changes for frontend
* add check for comments server
* add emoji mart package for emoji
* add reply count in comment sidebar
* subtract 1 from count in comment sidebar
* change empty text when no comments available
2021-11-01 07:28:03 +00:00
|
|
|
},
|
2021-10-02 05:52:02 +00:00
|
|
|
],
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
test: /\.scss$/,
|
2021-09-08 18:24:58 +00:00
|
|
|
use: [
|
|
|
|
|
{
|
|
|
|
|
loader: 'style-loader',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
loader: 'css-loader',
|
|
|
|
|
},
|
2024-06-18 09:24:30 +00:00
|
|
|
{
|
|
|
|
|
loader: 'postcss-loader',
|
|
|
|
|
},
|
2021-09-08 18:24:58 +00:00
|
|
|
{
|
|
|
|
|
loader: 'sass-loader',
|
2026-01-23 10:11:49 +00:00
|
|
|
options: {
|
|
|
|
|
sassOptions: {
|
|
|
|
|
silenceDeprecations: ['global-builtin', 'import', 'color-functions'],
|
|
|
|
|
},
|
|
|
|
|
},
|
2021-09-08 18:24:58 +00:00
|
|
|
},
|
|
|
|
|
],
|
2021-08-30 11:25:27 +00:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
test: /\.(js|jsx)$/,
|
|
|
|
|
exclude: /node_modules/,
|
|
|
|
|
resolve: {
|
2021-09-08 18:24:58 +00:00
|
|
|
extensions: ['.js', '.jsx'],
|
2021-08-30 11:25:27 +00:00
|
|
|
},
|
|
|
|
|
use: {
|
2021-09-17 14:04:15 +00:00
|
|
|
loader: 'babel-loader',
|
2021-09-15 15:52:53 +00:00
|
|
|
options: {
|
|
|
|
|
plugins: [
|
2025-08-03 07:09:18 +00:00
|
|
|
isDevEnv && require.resolve('react-refresh/babel'),
|
2026-01-23 10:11:49 +00:00
|
|
|
[
|
|
|
|
|
'import',
|
|
|
|
|
{
|
|
|
|
|
libraryName: 'lodash',
|
|
|
|
|
libraryDirectory: '',
|
|
|
|
|
camel2DashComponentName: false,
|
|
|
|
|
},
|
|
|
|
|
'lodash',
|
|
|
|
|
],
|
2025-08-03 07:09:18 +00:00
|
|
|
].filter(Boolean),
|
2021-09-15 15:52:53 +00:00
|
|
|
},
|
2021-09-17 14:04:15 +00:00
|
|
|
},
|
|
|
|
|
},
|
2022-05-10 09:39:09 +00:00
|
|
|
{
|
|
|
|
|
test: /\.html$/,
|
|
|
|
|
loader: 'html-loader',
|
|
|
|
|
},
|
2021-09-17 14:04:15 +00:00
|
|
|
],
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
2024-02-22 11:22:34 +00:00
|
|
|
plugins,
|
2021-04-30 08:10:57 +00:00
|
|
|
devServer: {
|
2022-03-01 07:55:51 +00:00
|
|
|
historyApiFallback: { index: ASSET_PATH },
|
2022-02-25 01:25:13 +00:00
|
|
|
static: {
|
|
|
|
|
directory: path.resolve(__dirname, 'assets'),
|
|
|
|
|
publicPath: '/assets/',
|
|
|
|
|
},
|
2026-01-23 10:11:49 +00:00
|
|
|
client: {
|
|
|
|
|
overlay: false,
|
|
|
|
|
},
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
|
|
|
|
output: {
|
2026-01-23 10:11:49 +00:00
|
|
|
filename: environment === 'production' ? '[name].[contenthash:8].js' : '[name].js',
|
|
|
|
|
chunkFilename: environment === 'production' ? '[name].[contenthash:8].chunk.js' : '[name].chunk.js',
|
|
|
|
|
assetModuleFilename: 'assets/[contenthash:8][ext][query]',
|
2022-03-01 07:55:51 +00:00
|
|
|
publicPath: ASSET_PATH,
|
2021-09-08 18:24:58 +00:00
|
|
|
path: path.resolve(__dirname, 'build'),
|
2026-01-23 10:11:49 +00:00
|
|
|
clean: true,
|
2021-04-30 08:10:57 +00:00
|
|
|
},
|
|
|
|
|
externals: {
|
|
|
|
|
// global app config object
|
|
|
|
|
config: JSON.stringify({
|
2022-08-29 10:19:39 +00:00
|
|
|
apiUrl: `${stripTrailingSlash(API_URL[environment]) || ''}/api`,
|
2025-02-25 06:52:50 +00:00
|
|
|
ENVIRONMENT: process.env.NODE_ENV,
|
2021-09-17 14:04:15 +00:00
|
|
|
SERVER_IP: process.env.SERVER_IP,
|
2022-10-23 06:41:27 +00:00
|
|
|
COMMENT_FEATURE_ENABLE: process.env.COMMENT_FEATURE_ENABLE ?? true,
|
2025-02-25 06:52:50 +00:00
|
|
|
TOOLJET_SERVER_URL: process.env.TOOLJET_SERVER_URL,
|
2022-05-06 06:59:50 +00:00
|
|
|
ENABLE_MULTIPLAYER_EDITING: true,
|
2023-03-24 11:35:08 +00:00
|
|
|
ENABLE_MARKETPLACE_DEV_MODE: process.env.ENABLE_MARKETPLACE_DEV_MODE,
|
2024-12-02 10:52:20 +00:00
|
|
|
TOOLJET_DB_BULK_UPLOAD_MAX_CSV_FILE_SIZE_MB: process.env.TOOLJET_DB_BULK_UPLOAD_MAX_CSV_FILE_SIZE_MB || 5,
|
2022-10-27 11:29:43 +00:00
|
|
|
TOOLJET_MARKETPLACE_URL:
|
|
|
|
|
process.env.TOOLJET_MARKETPLACE_URL || 'https://tooljet-plugins-production.s3.us-east-2.amazonaws.com',
|
2025-02-25 12:28:43 +00:00
|
|
|
TOOLJET_EDITION: process.env.TOOLJET_EDITION,
|
2025-02-25 06:52:50 +00:00
|
|
|
ENABLE_WORKFLOW_SCHEDULING: process.env.ENABLE_WORKFLOW_SCHEDULING,
|
2026-01-23 10:11:49 +00:00
|
|
|
WEBSITE_SIGNUP_URL: process.env.WEBSITE_SIGNUP_URL || 'https://www.tooljet.com/signup',
|
|
|
|
|
TJ_SELFHOST_CREDITS_APP:
|
|
|
|
|
process.env.TJ_SELFHOST_CREDITS_APP ||
|
|
|
|
|
'https://app.tooljet.com/applications/c1ec8a6c-ee9a-4a7d-ba9b-3590bbeaf6b9',
|
|
|
|
|
ENABLE_PASSWORD_COMPLEXITY_RULES: process.env.ENABLE_PASSWORD_COMPLEXITY_RULES || false,
|
2021-09-17 14:04:15 +00:00
|
|
|
}),
|
|
|
|
|
},
|
2021-04-30 08:10:57 +00:00
|
|
|
};
|