Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const https = require('https');
- const path = require('path');
- const fs = require('fs').promises;
- const _ = require('lodash');
- const cors = require('cors');
- const axios = require('axios').create({
- httpsAgent: new https.Agent({
- rejectUnauthorized: false,
- }),
- });
- const { getLogLevel, logError } = require('./logs');
- const locals = require('./locals');
- const cleanConfig = require('./cleanConfig');
- const prefixConfigUrls = require('./prefixConfigUrls');
- const reportLogResponse = require('./reportLogResponse');
- const urls = require('./urls.json');
- const optionalRequire = require('./optionalRequire');
- const httpsSettings = require('./httpsSettings');
- const FrameConfigPlugin = optionalRequire('@trans/frame-config-webpack-plugin');
- const TranslationsPlugin = optionalRequire('@trans/webpack-translations-plugin');
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
- const vendorPaths = {
- react: {
- development: 'react/umd/react.development.js',
- next: 'react.next/umd/react.development.js',
- },
- 'react-dom': {
- development: 'react-dom/umd/react-dom.development.js',
- next: 'react-dom.next/umd/react-dom.development.js',
- },
- };
- const defaultVendor = {
- react: 'development',
- 'react-dom': 'development',
- };
- const devServer = ({
- platform,
- mockTranslations = platform === undefined,
- host = 'platform.local.trans.eu',
- target = platform === 'prod' ? 'platform.trans.eu' : `platform.${platform ?? 'dev'}.trans.eu`,
- vendor = {},
- localConfig: {
- // function used to set loggedIn variable in filter
- // based on (transformed by transformBase) frameConfig
- checkIsLogged = ({ products: { basic } = {} } = {}) => !!basic,
- // Filter local config entries based on:
- // - module name
- // - is user logged in
- // - available products
- filter: filterLocalConfig = (moduleName, loggedIn) => loggedIn,
- // An object or a path to a file containing an object
- // that will be used to extend/override local configuration.
- extendConfig = {},
- // copy these keys from platform config to module/service config
- getFromPlatformConfig = [],
- } = {},
- localConfig,
- frameConfig: {
- // frame config url
- url: frameConfigUrl = urls.config,
- // Don't use platform config.
- // Base frame config only on local configs.
- ignorePlatformConfig = false,
- // Transform frame config from api before it is returned.
- transformBase = a => a,
- // Transform frame config before it is returned.
- transform = a => a,
- } = {},
- proxy: { context: proxyContext = '/', bypass = () => {}, ...proxyConfig } = {},
- before,
- stats = 'minimal',
- ...devServerConfig
- } = {}) => {
- const targetHost = `https://${target}`;
- const apiTargetHost = `https://api-${target}`;
- const platformConfigUrl = `${apiTargetHost}${frameConfigUrl}`;
- const logLevel = getLogLevel(stats);
- const vendorFiles = Object.entries({
- ...defaultVendor,
- ...vendor,
- })
- .reduce((files, entry) => {
- const file = _.get(vendorPaths, entry);
- if (file) {
- files.push(file);
- }
- return files;
- }, [])
- .map(lib => require.resolve(lib))
- .map(filePath => fs.readFile(filePath));
- const vendorContent = Promise.all(vendorFiles).then(files => Buffer.concat(files));
- let localTranslations = {};
- let translationsUrl = '';
- // Return WebPack Dev Server configuration
- return {
- hot: false,
- inline: false,
- http2: true,
- https: httpsSettings(host),
- historyApiFallback: true,
- disableHostCheck: true,
- host,
- stats,
- proxy: [
- {
- context: '/app',
- target: apiTargetHost,
- changeOrigin: true,
- secure: false,
- logLevel,
- },
- {
- context: proxyContext,
- target: targetHost,
- changeOrigin: true,
- secure: false,
- logLevel,
- bypass: (...args) => {
- const [req] = args;
- if (req.method === 'HEAD') {
- req.method = 'GET';
- }
- return bypass(...args);
- },
- ...proxyConfig,
- },
- ],
- before(app, server, compiler) {
- app.use(
- cors({
- origin: true,
- credentials: true,
- })
- );
- const configs = { module: {}, service: {}, layout: {} };
- const activeServers = locals(app, server, compiler);
- // Override vendor (react/react-dom) file
- // with requested version
- app.get('/dist/vendor.*.js', (req, res) => {
- vendorContent.then(content => res.send(content));
- });
- if (FrameConfigPlugin) {
- // Tap into hook from Frame Config Webpack Plugin
- // (https://git.dss.lt.trans/trans-web/frame-config-webpack-plugin)
- // and get config for local modules/services/layouts
- FrameConfigPlugin.getCompilerHooks(compiler).frameConfig.tap(
- 'devServer',
- (moduleName, type, config) => {
- configs[type][moduleName] = cleanConfig(config);
- }
- );
- FrameConfigPlugin.getHooks().frameConfig.tap('devServer', (moduleName, type, config) => {
- configs[type][moduleName] = cleanConfig(config);
- });
- }
- if (TranslationsPlugin) {
- // Tap into hook from TranslationsPlugin
- TranslationsPlugin.getHooks().translations.tap('devServer', translations => {
- localTranslations = translations;
- });
- }
- // Expose local config to other servers for internal use.
- app.get(urls.localConfig, (req, res) => {
- if (localConfig === false || !FrameConfigPlugin) {
- res.json({});
- return;
- }
- const localFrameConfig = { modules: {}, services: {}, routes: {}, layouts: {} };
- const logged = req.query.logged !== 'false';
- const products = req.query.products || [];
- Object.entries(configs).forEach(([type, list]) => {
- Object.entries(list).forEach(([moduleName, config]) => {
- const shouldFilter = type === 'module' || (type === 'service' && config?.data?.autostart);
- if (shouldFilter && !filterLocalConfig(moduleName, logged, products)) {
- return;
- }
- const { routes = [], ...moduleConfig } = cleanConfig(config);
- localFrameConfig[`${type}s`][moduleName] = moduleConfig;
- routes.forEach(({ name, ...routeConfig }) => {
- localFrameConfig.routes[name] = routeConfig;
- });
- });
- });
- let overrideConfig = extendConfig;
- // Import external file with config overrides
- if (_.isString(extendConfig)) {
- overrideConfig = require(extendConfig);
- // Delete from cache.
- // So each request fetches config again.
- delete require.cache[path.resolve(extendConfig)];
- }
- res.json(_.merge(localFrameConfig, overrideConfig));
- });
- // TODO: Temporary
- // app.get(frameConfigUrl, (req, res) => {
- // fs.readFile("mock-frameconfig.json", "utf-8").then(data => {
- // res.json(JSON.parse(data));
- // });
- // })
- app.get(frameConfigUrl, (req, res, next) => {
- const { host: _host, ...headers } = req.headers;
- // Get platform config.
- // Use authorization headers from original request.
- axios
- .get(platformConfigUrl, { headers, params: req.query })
- .then(({ data, config: { headers: responseHeaders, url } }) =>
- transformBase(data, { headers: responseHeaders, url })
- )
- .then(baseFrameConfig => {
- translationsUrl = baseFrameConfig?.config?.urls?.translations || '';
- const products = Object.keys((baseFrameConfig || {}).products || {});
- const logged = checkIsLogged(baseFrameConfig);
- const base = ignorePlatformConfig ? {} : baseFrameConfig;
- return Promise.all(
- // Collect local configuration from running servers.
- [...activeServers].map(clientPort => {
- const prefix = `${req.protocol}://${host}:${clientPort}`;
- const getConfigUrl = `${prefix}${urls.localConfig}`;
- return axios
- .get(getConfigUrl, { params: { logged, products } })
- .then(({ data }) => prefixConfigUrls(prefix, data))
- .catch(() => ({}));
- })
- )
- .then(frameConfigs => _.merge({}, ...frameConfigs))
- .then(localFrameConfig => {
- const { modules = {}, services = {}, layouts = {}, routes = {}, ...baseRest } = base;
- const {
- modules: localModules = {},
- services: localServices = {},
- layouts: localLayouts = {},
- routes: localRoutes = {},
- ...localRest
- } = localFrameConfig;
- // Don't merge modules and services
- // we want local modules/services to overwrite them
- const mergedConfig = _.merge({}, baseRest, localRest, {
- config: {
- urls: {
- reportLog: urls.reportLog,
- ...(mockTranslations &&
- TranslationsPlugin && {
- translations:
- urls.translations + '?language="[LANG]"&module="[MODULE]"',
- }),
- },
- },
- });
- [
- [localModules, modules],
- [localServices, services],
- [localLayouts, layouts],
- ].forEach(([local, remote]) => {
- const names = Object.keys(local);
- names.forEach(name => {
- const remoteKeys = _.isFunction(getFromPlatformConfig)
- ? getFromPlatformConfig(name)
- : getFromPlatformConfig;
- remoteKeys.forEach(key => {
- const val = (remote[name] || {})[key];
- if (!_.isEqual(local[name][key], val)) {
- local[name][key] = val;
- }
- });
- });
- // Put local modules/services first, so their externals will be registered first
- Object.assign(local, _.omit(remote, names));
- });
- Object.assign(mergedConfig, {
- modules: localModules,
- services: localServices,
- layouts: localLayouts,
- routes: {
- ...localRoutes,
- ..._.omit(routes, Object.keys(localRoutes)),
- },
- });
- res.json(transform(mergedConfig));
- });
- })
- .catch(error => next(error));
- });
- // TODO: Temporary
- // app.get(urls.translations, (req, res) => {
- // res.json({});
- // })
- app.get(urls.translations, (req, res) => {
- let { language, module: moduleName } = req.query;
- language = JSON.parse(language);
- moduleName = JSON.parse(moduleName);
- const proxyTranslationsUrl = translationsUrl
- .replace('[MODULE]', moduleName)
- .replace('[LANG]', language);
- const overridenTranslations = localTranslations?.[language]?.[moduleName];
- axios
- .get(proxyTranslationsUrl)
- .catch(() => ({}))
- .then(translations => {
- res.json({
- ...translations.data,
- ...overridenTranslations,
- });
- });
- });
- app.post(urls.reportLog, (req, res) => {
- new Promise(resolve => {
- let body = '';
- req.on('data', chunk => {
- body += chunk;
- });
- req.on('end', () => resolve(JSON.parse(body)));
- }).then(body => {
- res.send(reportLogResponse(body));
- body.forEach(({ type, message, payload = '' }) => {
- if (type === 'error') {
- logError(
- message,
- payload.status || _.get(payload, 'response.status', payload),
- payload.statusText || _.get(payload, 'response.statusText', '')
- );
- }
- });
- });
- });
- if (before) {
- before(app, server, compiler);
- }
- },
- ...devServerConfig,
- };
- };
- module.exports = devServer;
Advertisement
Add Comment
Please, Sign In to add comment