@kitchenshelf/serverless-rspack
Version:
[Serverless Framework](https://www.serverless.com) plugin for zero-config JavaScript and TypeScript code bundling using the high performance Rust-based JavaScript bundler [`rspack`](https://rspack.dev/guide/start/introduction)
165 lines • 7.48 kB
JavaScript
import { __awaiter } from "tslib";
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
import { DefinePlugin, ProgressPlugin, node, rspack, } from '@rspack/core';
import { writeFileSync } from 'node:fs';
import path from 'node:path';
import { cwd } from 'node:process';
import { mergeWithCustomize } from 'webpack-merge';
export function bundle(entries) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
let config;
if (this.providedRspackConfig && ((_a = this.pluginOptions.config) === null || _a === void 0 ? void 0 : _a.strategy)) {
this.log.verbose(`[Bundle] Config merge strategy: ${this.pluginOptions.config.strategy}`);
if (this.pluginOptions.config.strategy === 'combine') {
const baseConfig = defaultConfig(entries, this.pluginOptions, this.offlineMode, this.buildOutputFolderPath, this.log);
const mergedConfig = mergeWithCustomize({
customizeArray: mergeArrayUniqueStrategy(this.log),
})([baseConfig, this.providedRspackConfig]);
config = enforcePluginReadOnlyDefaults(mergedConfig, this.buildOutputFolderPath, entries);
}
else {
config = enforcePluginReadOnlyDefaults(this.providedRspackConfig, this.buildOutputFolderPath, entries);
}
}
else {
config = defaultConfig(entries, this.pluginOptions, this.offlineMode, this.buildOutputFolderPath, this.log);
}
this.log.verbose(`[Bundle] Bundling with config: ${safelyStringifyConfig(config)}`);
const startBundle = Date.now();
return new Promise((resolve) => {
rspack(config, (x, y) => {
var _a;
if (this.pluginOptions.stats) {
const c = y === null || y === void 0 ? void 0 : y.toJson();
try {
writeFileSync(path.join(this.buildOutputFolderPath, 'stats.json'), JSON.stringify(c));
}
catch (error) {
(_a = this.log) === null || _a === void 0 ? void 0 : _a.error(`[Bundle] Failed to write stats file: ${error}`);
}
}
this.log.verbose(`[Performance] Bundle total execution time for service ${this.serverless.service.service} [${Date.now() - startBundle} ms]`);
resolve('Success!'); // Yay! Everything went well!
});
});
});
}
const esmOutput = {
chunkFormat: 'module',
chunkLoading: 'import',
library: {
type: 'module',
},
};
const defaultConfig = (entries, buildOptions, offlineMode, workFolderPath, logger) => {
var _a, _b;
return (Object.assign(Object.assign({ mode: buildOptions.mode, entry: entries, target: 'node', experiments: {
outputModule: buildOptions.esm,
}, devtool: buildOptions.sourcemap !== undefined ? buildOptions.sourcemap : false, resolve: Object.assign({ extensions: ['...', '.ts', '.tsx', '.jsx'] }, (buildOptions.tsConfig
? {
tsConfig: path.resolve(cwd(), buildOptions.tsConfig),
}
: {})) }, (((_a = buildOptions.externals) === null || _a === void 0 ? void 0 : _a.length) && ((_b = buildOptions.externals) === null || _b === void 0 ? void 0 : _b.length) > 0
? {
externals: [
({ request }, callback) => {
var _a;
const isExternal = (_a = buildOptions === null || buildOptions === void 0 ? void 0 : buildOptions.externals) === null || _a === void 0 ? void 0 : _a.some((external) => {
return new RegExp(external).test(request);
});
if (isExternal) {
logger.verbose(`[Bundle] Marking ${request} as external`);
return callback(null, 'node-commonjs ' + request);
}
callback();
},
],
}
: {})), { plugins: [
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env['NODE_ENV']),
}),
new ProgressPlugin({}),
new node.NodeTargetPlugin(),
createDoctorPlugin(buildOptions),
].filter(Boolean), module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
target: 'es2020',
parser: {
syntax: 'typescript',
},
},
},
},
},
],
}, optimization: {
mangleExports: false,
}, output: Object.assign(Object.assign({ path: workFolderPath, library: { type: 'commonjs2' } }, (buildOptions.esm ? esmOutput : {})), (offlineMode
? { devtoolModuleFilenameTemplate: '[absolute-resource-path]' }
: {})) }));
};
function mergeArrayUniqueStrategy(logger) {
return (base, provided, key) => {
if (key === 'plugins' && isPlugins(base) && isPlugins(provided)) {
const plugins = [...provided];
base.forEach((basePlugin) => {
const matchedPlugin = provided.find((providedPlugin) => basePlugin.name === providedPlugin.name);
if (matchedPlugin) {
logger.warning(`[Bundle] You have provided your own ${matchedPlugin.name}. This will override the default one provided by @kitchenshelf/serverless-rspack.`);
}
else {
plugins.push(basePlugin);
}
});
return plugins;
}
// Fall back to default merging
return undefined;
};
}
const enforcePluginReadOnlyDefaults = (config, buildOutputFolderPath, entries) => {
return Object.assign(Object.assign({}, config), { entry: entries, optimization: Object.assign(Object.assign({}, config.optimization), { mangleExports: false }), output: Object.assign(Object.assign({}, config.output), { path: buildOutputFolderPath }) });
};
function isPlugins(a) {
return Array.isArray(a);
}
function createDoctorPlugin(buildOptions) {
const isEnabled = enabledViaSimpleConfig(buildOptions.doctor) ||
enabledViaConfigObject(buildOptions.doctor);
return isEnabled
? new RsdoctorRspackPlugin({
disableClientServer: true,
mode: 'brief',
reportDir: getReportDir(buildOptions.doctor),
})
: null;
}
function enabledViaSimpleConfig(doctor) {
return typeof doctor === 'boolean' && doctor === true;
}
function enabledViaConfigObject(doctor) {
return (typeof doctor === 'object' && doctor !== null && doctor.enable === true);
}
function getReportDir(doctor) {
if (enabledViaConfigObject(doctor) && doctor.outputDirectory) {
return doctor.outputDirectory;
}
return undefined;
}
function safelyStringifyConfig(config) {
return JSON.stringify(config, (key, value) => {
if (key === 'plugins') {
return value.map((plugin) => plugin.constructor.name);
}
return value;
});
}
//# sourceMappingURL=bundle.js.map