Skip to content

Commit

Permalink
Fixes #37252 - prevent duplicate foremanReact in plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
MariaAga authored and evgeni committed Apr 11, 2024
1 parent a88d8d3 commit 4550a0c
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 4 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Expand Up @@ -23,6 +23,7 @@
"ascii",
"auditable",
"Autocompletion",
"autogenerated",
"bool",
"bootable",
"Borderless",
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -54,4 +54,5 @@ npm-debug.log
.solargraph.yml
.nvmrc
mkmf.log
.yardoc/
.yardoc/
webpack/assets/javascripts/all_react_app_exports.js
1 change: 1 addition & 0 deletions app/views/layouts/base.html.erb
Expand Up @@ -39,6 +39,7 @@
<%= get_webpack_foreman_vendor_js %>
<%= javascript_include_tag('/webpack/vendor.js') %>
<%= javascript_include_tag('/webpack/bundle.js') %>
<%= javascript_include_tag('/webpack/reactExports.js') %>
<%= javascript_include_tag 'application' %>
<%= webpacked_plugins_with_global_js %>
Expand Down
27 changes: 27 additions & 0 deletions config/webpack.config.js
Expand Up @@ -12,6 +12,7 @@ var vendorEntry = require('./webpack.vendor');
var fs = require('fs');
const { ModuleFederationPlugin } = require('webpack').container;
var pluginUtils = require('../script/plugin_webpack_directories');
var { generateExportsFile }= require('../webpack/assets/javascripts/exportAll');

class AddRuntimeRequirement {
// to avoid "webpackRequire.l is not a function" error
Expand Down Expand Up @@ -153,10 +154,19 @@ const coreConfig = function() {
config.entry = {
bundle: { import: bundleEntry, dependOn: 'vendor' },
vendor: vendorEntry,
reactExports: path.join(
__dirname,
'..',
'webpack/assets/javascripts/all_react_app_exports.js'
),
};
config.output = {
path: path.join(__dirname, '..', 'public', 'webpack'),
publicPath: '/webpack/',
library: {
name: ['TheForeman', '[name]'],
type: 'var',
},
};
var plugins = config.plugins;

Expand Down Expand Up @@ -196,6 +206,21 @@ const pluginConfig = function(plugin) {
var config = commonConfig();
config.context = path.join(pluginRoot, 'webpack');
config.entry = {};

function convertImportStatement(importStatement) {
const importPath = importStatement;
const importPathParts = importPath.split('/');
const newImportName = importPathParts.slice(1).join('_');
return newImportName;
}
config.externals = function({ request }, callback) {
if (/^foremanReact(\/.*)?$/.test(request)) {
const prefix = 'var TheForeman.reactExports.';
const newPath = prefix + convertImportStatement(request.substring('foremanReact'.length));
return callback(null, newPath);
}
return callback();
};
var pluginEntries = {
'./index': path.resolve(pluginRoot, 'webpack', 'index'),
};
Expand Down Expand Up @@ -233,6 +258,7 @@ const pluginConfig = function(plugin) {

//get the list of webpack plugins
var plugins = config.plugins;

plugins.push(
new ModuleFederationPlugin({
name: pluginName,
Expand Down Expand Up @@ -262,6 +288,7 @@ const pluginConfig = function(plugin) {
};

module.exports = function(env, argv) {
generateExportsFile();
const { pluginName } = env;
var pluginsDirs = pluginUtils.getPluginDirs('pipe');
var pluginsInfo = {};
Expand Down
62 changes: 62 additions & 0 deletions webpack/assets/javascripts/exportAll.js
@@ -0,0 +1,62 @@
const fs = require('fs');
const path = require('path');

function generateExports(directoryPath, exportFileContent = '') {
fs.readdirSync(directoryPath, { withFileTypes: true }).forEach(dirent => {
if (
dirent.isDirectory() &&
dirent.name !== '__mocks__' &&
dirent.name !== '__tests__'
) {
const subDirectoryPath = path.join(directoryPath, dirent.name);
exportFileContent = generateExports(subDirectoryPath, exportFileContent);
} else if (dirent.isFile()) {
const fileNameWithoutExtension = path.parse(dirent.name).name;
const fileExtension = path.parse(dirent.name).ext;

if (
fileExtension === '.js' &&
!dirent.name.endsWith('.test.js') &&
!dirent.name.endsWith('.fixtures.js') &&
!dirent.name.endsWith('mockRequests.js') &&
!fileNameWithoutExtension.includes('TestHelper') &&
!fileNameWithoutExtension.includes('testHelper') &&
!fileNameWithoutExtension.includes('APITestSetup')
) {
let relativeFilePath = path.relative(
__dirname,
path.join(directoryPath, fileNameWithoutExtension)
);
relativeFilePath = relativeFilePath.substring(
relativeFilePath.indexOf('react_app') + 'react_app'.length + 1
);
let fileName = relativeFilePath.replace(/\\/g, '/').replace(/\//g, '_'); // replace slashes with underscores
fileName = fileName.replace(/\./g, ''); // remove dots

if (fileName.endsWith('_index')) {
fileName = fileName.substring(0, fileName.length - '_index'.length); // remove _index
}

exportFileContent += `import * as ${fileName} from './react_app/${relativeFilePath.replace(
/\\/g,
'/'
)}';\n`;
exportFileContent += `export { ${fileName} };\n`;
}
}
});

return exportFileContent;
}

const generateExportsFile = () => {
let exportFileContent = generateExports(path.join(__dirname, 'react_app'));
exportFileContent = `/* eslint-disable */\n// This file is autogenerated by the webpack/assets/javascripts/exportAll.js script\n// Please do not modify this file directly\n\n${exportFileContent}`;

fs.writeFileSync(
path.join(__dirname, 'all_react_app_exports.js'),
exportFileContent
);
};

module.exports = { generateExportsFile };
9 changes: 6 additions & 3 deletions webpack/assets/javascripts/react_app/mockRequests.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import { MockAdapter } from '@theforeman/test';

export const mock = new MockAdapter(axios);
export const mock = () => new MockAdapter(axios);
const methods = {
GET: 'onGet',
POST: 'onPost',
Expand All @@ -15,6 +15,9 @@ export const mockRequest = ({
data = null,
status = 200,
response = null,
}) => mock[methods[method]](url, data).reply(status, response);
}) =>
mock()
[methods[method]](url, data)
.reply(status, response);

export const mockReset = () => mock.reset();
export const mockReset = () => mock().reset();

0 comments on commit 4550a0c

Please sign in to comment.