notebook/app/webpack.config.js
Jeremy Tuloup 2047e3a5e4
Rename to RetroLab (#121)
* Rename text to RetroLab

* More renaming

* More renaming

* Rename files

* Update deps

* Update logo

* Lint

* Update README.md

* Minor CSS fix

* Update tour

* Update screencasts in README.md
2021-05-19 15:13:00 +02:00

180 lines
5.3 KiB
JavaScript

// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
// Heavily inspired (and slightly tweaked) from:
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/webpack.config.js
const fs = require('fs-extra');
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge').default;
const { ModuleFederationPlugin } = webpack.container;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin;
const Build = require('@jupyterlab/builder').Build;
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
const data = require('./package.json');
const names = Object.keys(data.dependencies).filter(name => {
const packageData = require(path.join(name, 'package.json'));
return packageData.jupyterlab !== undefined;
});
// Ensure a clear build directory.
const buildDir = path.resolve(__dirname, 'build');
if (fs.existsSync(buildDir)) {
fs.removeSync(buildDir);
}
fs.ensureDirSync(buildDir);
// Copy extra files
const index = path.resolve(__dirname, 'index.js');
const cssImports = path.resolve(__dirname, 'style.js');
fs.copySync(index, path.resolve(buildDir, 'index.js'));
fs.copySync(cssImports, path.resolve(buildDir, 'extraStyle.js'));
const extras = Build.ensureAssets({
packageNames: names,
output: buildDir
});
/**
* Create the webpack ``shared`` configuration
*/
function createShared(packageData) {
// Set up module federation sharing config
const shared = {};
const extensionPackages = packageData.jupyterlab.extensions;
// Make sure any resolutions are shared
for (let [pkg, requiredVersion] of Object.entries(packageData.resolutions)) {
shared[pkg] = { requiredVersion };
}
// Add any extension packages that are not in resolutions (i.e., installed from npm)
for (let pkg of extensionPackages) {
if (!shared[pkg]) {
shared[pkg] = {
requiredVersion: require(`${pkg}/package.json`).version
};
}
}
// Add dependencies and sharedPackage config from extension packages if they
// are not already in the shared config. This means that if there is a
// conflict, the resolutions package version is the one that is shared.
const extraShared = [];
for (let pkg of extensionPackages) {
let pkgShared = {};
let {
dependencies = {},
jupyterlab: { sharedPackages = {} } = {}
} = require(`${pkg}/package.json`);
for (let [dep, requiredVersion] of Object.entries(dependencies)) {
if (!shared[dep]) {
pkgShared[dep] = { requiredVersion };
}
}
// Overwrite automatic dependency sharing with custom sharing config
for (let [dep, config] of Object.entries(sharedPackages)) {
if (config === false) {
delete pkgShared[dep];
} else {
if ('bundled' in config) {
config.import = config.bundled;
delete config.bundled;
}
pkgShared[dep] = config;
}
}
extraShared.push(pkgShared);
}
// Now merge the extra shared config
const mergedShare = {};
for (let sharedConfig of extraShared) {
for (let [pkg, config] of Object.entries(sharedConfig)) {
// Do not override the basic share config from resolutions
if (shared[pkg]) {
continue;
}
// Add if we haven't seen the config before
if (!mergedShare[pkg]) {
mergedShare[pkg] = config;
continue;
}
// Choose between the existing config and this new config. We do not try
// to merge configs, which may yield a config no one wants
let oldConfig = mergedShare[pkg];
// if the old one has import: false, use the new one
if (oldConfig.import === false) {
mergedShare[pkg] = config;
}
}
}
Object.assign(shared, mergedShare);
// Transform any file:// requiredVersion to the version number from the
// imported package. This assumes (for simplicity) that the version we get
// importing was installed from the file.
for (let [pkg, { requiredVersion }] of Object.entries(shared)) {
if (requiredVersion && requiredVersion.startsWith('file:')) {
shared[pkg].requiredVersion = require(`${pkg}/package.json`).version;
}
}
// Add singleton package information
for (let pkg of packageData.jupyterlab.singletonPackages) {
if (shared[pkg]) {
shared[pkg].singleton = true;
}
}
return shared;
}
// Make a bootstrap entrypoint
const entryPoint = path.join(buildDir, 'bootstrap.js');
const bootstrap = 'import("./index.js");';
fs.writeFileSync(entryPoint, bootstrap);
if (process.env.NODE_ENV === 'production') {
baseConfig.mode = 'production';
}
if (process.argv.includes('--analyze')) {
extras.push(new BundleAnalyzerPlugin());
}
module.exports = [
merge(baseConfig, {
mode: 'development',
entry: ['./publicpath.js', './' + path.relative(__dirname, entryPoint)],
output: {
path: path.resolve(__dirname, '..', 'retrolab/static/'),
library: {
type: 'var',
name: ['_JUPYTERLAB', 'CORE_OUTPUT']
},
filename: 'bundle.js'
},
plugins: [
new ModuleFederationPlugin({
library: {
type: 'var',
name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
},
name: 'CORE_FEDERATION',
shared: createShared(data)
})
]
})
].concat(extras);