I am trying to use webpack to bundle a few libraries into my typescript suitelet
.
Netsuite expects suitescripts to follow amd
modules pattern. If I use tsc
tocompile my suitelet, I get correct syntax that looks this fragment:
/**
*
* @NApiVersion 2.x
* @NScriptType Suitelet
*/
define(["require", "exports", "N", "N/file"], function (require, exports, N_1, file_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onRequest = void 0;
var onRequest = function (context) {
//my actual code here
};
exports.onRequest = onRequest;
});
The poblem is that the dependencies from node_modules are not bundled. So I have tried to use webpack for this, and webpack output differs:
/**
*
* @NApiVersion 2.x
* @NScriptType Suitelet
*/
define(["N", "N/file"], (__WEBPACK_EXTERNAL_MODULE__N, __WEBPACK_EXTERNAL_MODULE__Nfile) => {
return (() => {
//... some webpack internals goes here
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */
__webpack_require__.d(__webpack_exports__, {
/* harmony export */ "onRequest": () => (/* binding */ onRequest)
// harmony imports goes here, cut for readability
});
var onRequest = function onRequest(context) {
//my actual code here
};
})();
return __webpack_exports__;
})();
});
Netsuite does not accept the version webpack produces. I assume that the problem is that webpack return
s the exported module, but Netsuite expect's it to be passed as the 2nd parameter to the module factory function and modified by it. tsc
does that. It modifies the export
parameter adding the onRequest
function to the export
object. Webpack just return new object.
How should I configure webpack to follow the define(["require","exports","other-dependencies"], factory_function);
convention?
Here are the fragments of my webpack.config.js
:
module.exports = {
entry: glob.sync('.src/**.ts').reduce((obj, el) => {
obj[path.parse(el).name] = el;
return obj;
}, {}),
output: {
filename: '[name].js',
libraryTarget: 'amd',
path: path.resolve(__dirname, 'dist'),
globalObject: 'this',
},
resolve: {
extensions: ['.ts', '.js'],
modules: [
path.resolve(__dirname, 'node_modules'),
'node_modules'
]
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'babel-loader',
},
],
},
optimization: {
// Do not remove the SuiteScript JSDoc when minifying
minimize: false,
minimizer: [
new TerserPlugin({
terserOptions: {
output: {
comments: /@NApiVersion/i,
},
},
}),
],
},
plugins: [
// Copy the SuiteScript JSDoc to the top of the script
new webpack.BannerPlugin({
banner: data => {
const filename = data.chunk.entryModule.resource;
const contents = fs.readFileSync(filename, 'UTF-8');
const comments = contents.match(/\/\*[\s\S]*?\*\//);
return comments.length ? comments[0] : '';
},
raw: true,
}),
],
externals: [/^N\//, /^N$/],
externalsType: 'umd'
};