Skip to content

⚗️(front) conditionaly install blocknote xl packages #845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
node-version: ${{ inputs.node_version }}
- name: Install dependencies
if: steps.front-node_modules.outputs.cache-hit != 'true'
run: cd src/frontend/ && yarn install --frozen-lockfile
run: cd src/frontend/ && AUTO_INSTALL_EXTRA_DEPS=true yarn install --frozen-lockfile
- name: Cache install frontend
if: steps.front-node_modules.outputs.cache-hit != 'true'
uses: actions/cache@v4
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ services:
Y_PROVIDER_URL: "ws://localhost:4444"
MEDIA_URL: "http://localhost:8083"
SW_DEACTIVATED: "true"
AUTO_INSTALL_EXTRA_DEPS: "true"
image: impress:frontend-development
ports:
- "3000:3000"
Expand Down
5 changes: 4 additions & 1 deletion src/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
FROM node:20-alpine AS frontend-deps

ARG AUTO_INSTALL_EXTRA_DEPS=false

WORKDIR /home/frontend/

COPY ./src/frontend/package.json ./package.json
COPY ./src/frontend/bin/conditional-install.js ./bin/conditional-install.js
COPY ./src/frontend/yarn.lock ./yarn.lock
COPY ./src/frontend/apps/impress/package.json ./apps/impress/package.json
COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslint-config-impress/package.json

RUN yarn install --frozen-lockfile
RUN AUTO_INSTALL_EXTRA_DEPS=${AUTO_INSTALL_EXTRA_DEPS} yarn install --frozen-lockfile

COPY .dockerignore ./.dockerignore
COPY ./src/frontend/.prettierrc.js ./.prettierrc.js
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/apps/impress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
"@blocknote/core": "0.23.2-hotfix.0",
"@blocknote/mantine": "0.23.2-hotfix.0",
"@blocknote/react": "0.23.2-hotfix.0",
"@blocknote/xl-docx-exporter": "0.23.2-hotfix.0",
"@blocknote/xl-pdf-exporter": "0.23.2-hotfix.0",
"@fontsource/material-icons": "5.2.5",
"@gouvfr-lasuite/integration": "1.0.2",
"@gouvfr-lasuite/ui-kit": "0.1.3",
Expand Down Expand Up @@ -79,5 +77,9 @@
"typescript": "*",
"webpack": "5.98.0",
"workbox-webpack-plugin": "7.1.0"
},
"extraDependencies": {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add this comment here:

// The XL packages are dual-licensed by the author of BlockNote under
// AGPL-3.0 or a proprietary license. If you install them, you need to
// fulfill your licensing obligations.

"@blocknote/xl-docx-exporter": "0.23.2-hotfix.0",
"@blocknote/xl-pdf-exporter": "0.23.2-hotfix.0"
Comment on lines +81 to +83
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to do that, neither to have a conditional-install I think , just by setting a env var at build time and have a conditional import, with the tree shaking the packages will be excluded from the final build.

import dynamic from 'next/dynamic';

let Component = null;

if (process.env.WITH_AGPL_PACKAGES === 'true') {
  Component = dynamic(() => import('blocknote-xl-package'));
} else {
  Component = dynamic(() => import('blocknote-packag'));
}

export default function Whatever() {
  return <Component />;
}

Then here, before the yarn build:

ARG SW_DEACTIVATED
ENV NEXT_PUBLIC_SW_DEACTIVATED=${SW_DEACTIVATED}
RUN yarn build

You have to add this env var:

...
ARG SW_DEACTIVATED
ENV NEXT_PUBLIC_SW_DEACTIVATED=${SW_DEACTIVATED}

ARG WITH_AGPL_PACKAGES 
ENV WITH_AGPL_PACKAGES =${WITH_AGPL_PACKAGES }

RUN yarn build
...

The final code just take what is used by the app, we don't have node_modules anymore in the image:

COPY --from=impress-builder \
/home/frontend/apps/impress/out \
/usr/share/nginx/html

}
}
139 changes: 139 additions & 0 deletions src/frontend/bin/conditional-install.js
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest install-extras.js as a more explicit name.

Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const readline = require('readline');

// Check if AUTO_INSTALL_EXTRA_DEPS is explicitly set to false
if (process.env.AUTO_INSTALL_EXTRA_DEPS === 'false') {
console.log('AUTO_INSTALL_EXTRA_DEPS is set to false, skipping script execution');
process.exit(0);
}

// Get the workspace root directory
const workspaceRoot = process.cwd();

// Check if AUTO_INSTALL_EXTRA_DEPS environment variable is set to bypass prompts
const autoMode = process.env.AUTO_INSTALL_EXTRA_DEPS === 'true';

// Create readline interface for user prompts
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

// Function to prompt user for confirmation
function promptUser(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer.toLowerCase().startsWith('y'));
});
});
}

// Function to find all package.json files in the apps directory
function findPackageJsonFiles(directory) {
const appsDir = path.join(workspaceRoot, directory);

// Check if the directory exists
if (!fs.existsSync(appsDir)) {
console.log(`Directory ${directory} does not exist, skipping...`);
return [];
}

const packageJsonFiles = [];

// Read all items in the directory
const items = fs.readdirSync(appsDir);

for (const item of items) {
const itemPath = path.join(appsDir, item);
const stat = fs.statSync(itemPath);

if (stat.isDirectory()) {
// Check if this directory has a package.json
const packageJsonPath = path.join(itemPath, 'package.json');
if (fs.existsSync(packageJsonPath)) {
packageJsonFiles.push(packageJsonPath);
// Skip searching in subdirectories once a package.json is found
continue;
}

// Only search subdirectories if no package.json was found in this directory
packageJsonFiles.push(...findPackageJsonFiles(path.join(directory, item)));
}
}

return packageJsonFiles;
}

// Find all package.json files in the apps directory
const packageJsonFiles = findPackageJsonFiles('apps');

if (packageJsonFiles.length === 0) {
console.log('No package.json files found in the apps directory');
process.exit(0);
}

console.log(`Found ${packageJsonFiles.length} package.json files in the apps directory`);

// Process each package.json file
async function processPackageJsonFiles() {
for (const packageJsonPath of packageJsonFiles) {
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));

// Check if extraDependencies exists
if (packageJson.extraDependencies && Object.keys(packageJson.extraDependencies).length > 0) {
console.log(`Found extraDependencies in ${packageJsonPath}, installing...`);

// Process each dependency individually
for (const [pkg, version] of Object.entries(packageJson.extraDependencies)) {
const dependencyToInstall = `${pkg}@${version}`;

// Prompt user if not in auto mode
let shouldInstall = autoMode;
if (!autoMode) {
shouldInstall = await promptUser(`
Do you want to install ${dependencyToInstall}? (y/n):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest this:

Do you want to install ${dependencyToInstall}? (y/n): 
These packages are dual-licensed by the author of BlockNote under
AGPL-3.0 or a proprietary license. If you install them, you need to
fulfill your licensing obligations.

Note that these packages are dual-licensed by Blocknotejs
under AGPL-3.0 or a proprietary license. If you choose
to install them, please ensure you fulfill your licensing
obligations with respect to BlockNoteJS
`);
}

if (shouldInstall) {
// Install the dependency using npm install
try {
console.log(`Installing: ${dependencyToInstall}`);
execSync(`npm install --no-save --ignore-scripts --no-audit ${dependencyToInstall}`, { stdio: 'inherit' });
console.log(`Extra dependency ${dependencyToInstall} installed successfully`);
} catch (error) {
console.error(`Failed to install extra dependency ${dependencyToInstall}:`, error.message);
// Continue with other dependencies even if one fails
}
} else {
console.log(`Skipping installation of ${dependencyToInstall}`);
}
}
} else {
console.log(`No extraDependencies found in ${packageJsonPath}, skipping installation`);
}
} catch (error) {
console.error(`Error reading or parsing ${packageJsonPath}:`, error.message);
// Continue with other package.json files even if one fails
}
}

console.log('Finished processing all package.json files');
rl.close();
}

// Run the async function
processPackageJsonFiles().catch(error => {
console.error('An error occurred:', error);
rl.close();
process.exit(1);
});
3 changes: 2 additions & 1 deletion src/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"i18n:deploy": "yarn I18N run format-deploy && yarn APP_IMPRESS prettier",
"i18n:test": "yarn I18N run test",
"test": "yarn server:test && yarn app:test",
"server:test": "yarn COLLABORATION_SERVER run test"
"server:test": "yarn COLLABORATION_SERVER run test",
"postinstall": "node ./bin/conditional-install.js"
},
"resolutions": {
"@types/node": "22.13.9",
Expand Down
Loading
Loading