Reputation: 913
I want to build some TypeScript code by Webpack and make it available inside Pug inline code like:
-
const { formatNumberWith4KetaKanji } = global.__EXPORTS_FROM_LIBRARY__;
const test = 1;
functionFromTheLibrary(test)
Please note that this functinality must be distibuted via Pug files. It means that usage of locals
of Pug API is not acceptable.
In the question Which JavaScript runtime the Pug 3.X using? I tried to get the info about JavaScript runtime of Pug, but for this moment, it still unanswered.
We can exclude the Pug from this problem and the question will become to "How to build importable bundle of Webpack from TypeScript which does not using neither window
nor module
objects"? I suppose, if I asked such as, I was given the instructions to explaing why I need it.
Try to provide the function separateEach3DigitsGroupWithComma from the Yamato Daiwa ES Extensions library. The source TypeScript file is:
export { separateEach3DigitsGroupWithComma } from "@yamato-daiwa/es-extensions";
Once it will be compiled to JavaScript, we can write this code to .pug
file with leading en dash (I already implemented this automation):
-
// compiled JavaScript code here ...
Now, if to setup the Webpack correctly, we can take above function as:
include GeneratedExports.pug
-
const { separateEach3DigitsGroupWithComma } = global.__PUG_EXTENSIONS_EXPORTS__;
.ProductCard
.ProductCard-Title Lamborghini Urus
.ProductCard-PriceLabel= separateEach3DigitsGroupWithComma(211321)
Generated code:
! function(e, t) {
"object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.__PUG_EXTENSIONS_EXPORTS__ = t() : e.__PUG_EXTENSIONS_EXPORTS__ = t()
}(self, (() => (() => {
"use strict";
var e = {
d: (t, o) => {
for (var r in o) e.o(o, r) && !e.o(t, r) && Object.defineProperty(t, r, {
enumerable: !0,
get: o[r]
})
},
o: (e, t) => Object.prototype.hasOwnProperty.call(e, t),
r: e => {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value: !0
})
}
},
t = {};
function o(e) {
return String(e).replace(/\B(?=(?:\d{3})+(?!\d))/gu, ",")
}
return e.r(t), e.d(t, {
separateEach3DigitsGroupWithComma: () => o
}), t
})()));
Pug compilation error:
Cannot set properties of undefined (setting '__PUG_EXTENSIONS_EXPORTS__')
Maybe it refers to exports.__PUG_EXTENSIONS_EXPORTS__
or to e.__PUG_EXTENSIONS_EXPORTS__
. Both exports
and e
are undefined (in the Pug runtime).
Generated code:
!function(e, o) {
"object" == typeof exports && "object" == typeof module ? module.exports = o() : "function" == typeof define && define.amd ? define([], o) : "object" == typeof exports ? exports.__PUG_EXTENSIONS_EXPORTS__ = o() : e.__PUG_EXTENSIONS_EXPORTS__ = o()
}(global, (() => (() => {
"use strict";
var e = {
d: (o, t) => {
for (var r in t) e.o(t, r) && !e.o(o, r) && Object.defineProperty(o, r, {
enumerable: !0,
get: t[r]
})
},
o: (e, o) => Object.prototype.hasOwnProperty.call(e, o),
r: e => {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value: !0
})
}
},
o = {};
e.r(o), e.d(o, {
separateEach3DigitsGroupWithComma: () => t.separateEach3DigitsGroupWithComma
});
const t = require("@yamato-daiwa/es-extensions");
return o
})()));
TypeScript error:
require is not a function
I have working code sample which has been generated a log time ago. The first lines of the code are pretty similar...
Currently it's unclear which webpack config I have used, but it was actual for the old webpack.
!function(e, t) {
"object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.__PUG_EXTENSIONS_EXPORTS__ = t() : e.__PUG_EXTENSIONS_EXPORTS__ = t()
}(global, (function() {
return (() => {
"use strict";
var e = {
d: (t, r) => {
for (var n in r) e.o(r, n) && !e.o(t, n) && Object.defineProperty(t, n, {
enumerable: !0,
get: r[n]
})
},
o: (e, t) => Object.prototype.hasOwnProperty.call(e, t),
r: e => {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(e, "__esModule", {
value: !0
})
}
},
t = {};
function r(e) {
return function(e, t) {
return Array.from(e)
}(e).reverse().join("")
}
function n(e) {
return void 0 === e
}
function o(e) {
let t = e.toString();
const o = t.startsWith("-"),
u = t.split(".")[1];
if (t.length < 5) return t;
o && (t = t.substring(1)), n(u) || (t = t.replace(`.${u}`, ""));
const i = r(t),
a = r(i.substr(0, 4)),
l = r(i.substr(4, 4)),
s = r(i.substr(8, 4)),
c = r(i.substr(12, 4)),
f = r(i.substr(16, 4)),
m = r(i.substr(20));
return (o ? "-" : "") + (m.length > 0 ? `${m}` : "") + (f.length > 0 ? `${f}δΊ¬` : "") + (c.length > 0 ? `${c}ε
` : "") + (s.length > 0 ? `${s}ε` : "") + (l.length > 0 ? `${l}δΈ` : "") + `${a}` + (n(u) ? "" : `.${u}`)
}
function u(e) {
return /^[1-9][0-9]*$/u.test(e)
}
function i(e) {
return String(e).replace(/\B(?=(?:\d{3})+(?!\d))/gu, ",")
}
function a(e) {
return String(e).replace(/\B(?=(?:\d{4})+(?!\d))/gu, ",")
}
function l(e) {
return e.replace(/\s{2,}/gmu, " ")
}
function s({
minimalValue: e,
maximalValue: t
}) {
return Math.floor(Math.random() * (t - e + 1) + e)
}
function c(e) {
return e[s({
minimalValue: 0,
maximalValue: e.length - 1
})]
}
function f() {
return Math.random() >= .5
}
function m(e) {
return `mailto:${e}`
}
function g(e) {
return `tel:${e}`
}
return e.r(t), e.d(t, {
buildEmailLinkHREF_ArttributeValue: () => m,
buildPhoneNumberLinkHREF_ArttributeValue: () => g,
formatNumberWith4KetaKanji: () => o,
getRandomArrayElement: () => c,
getRandomBoolean: () => f,
getRandomInteger: () => s,
isStringifiedNonNegativeIntegerOfRegularNotation: () => u,
replace2OrMoreSpacesTo1: () => l,
separateEach3DigitsGroupWithComma: () => i,
separateEach4DigitsGroupWithComma: () => a
}), t
})()
}));
Upvotes: 0
Views: 306
Reputation: 19957
TL;DR: According to the doc, you need to set output.globalObject
. This config should work:
output.target = "web" // default
output.library.type = "umd"
output.library.name = "PUG_EXTENSIONS_EXPORTS"
output.globalObject = "this" // or "globalThis"
A closer look to your 2 attempts I find them differ in 2 places.
self
, (b) "node" uses global
require
to link package.You want combination of (b) and (c), that's the config I provide above. Problem solved.
Below is me sharing a detour during investigation, which uncovers some technical details in Pug engine, and eventually winds up at a piece of probably lesser known info.
TL;DR: require
is NOT global variable in Node.js (nor are module, exports, __dirname, __filename
).
I know for a fact that Pug is just using Node.js as runtime, that explains 1st error:
Cannot set properties of undefined (setting '__PUG_EXTENSIONS_EXPORTS__')
Cus in Node.js self
does not point to global object. However I don't understand the 2nd error:
require is not a function
Why? π€ I thought require
is global variable in Node.js.
Out of curiosity I did a bit of code forensics and find out the reason. Check here link.
In essence, Pug works like this:
var pugTemplate = fs.readFileSync('./template.pug', 'utf8');
var renderer = pug.compile(pugTemplate, options);
var html = renderer(locals);
Tricky thing is how Pug compile. It use Function constructor to create the renderer
function.
// slightly simplified, not actual implementation
var js = pug.compileBody(pugTemplate, options);
var renderer = new Function('', js);
Which, if applied to your code, would look sth like:
var js = `
var pug_html = "";
!function(e, t) {
e.__PUG_EXTENSIONS_EXPORTS__ = t();
}(global, (() => {
"use strict";
var t = require("@yamato-daiwa/es-extensions");
var _exports = {
separateEach3DigitsGroupWithComma: t.separateEach3DigitsGroupWithComma;
};
return _exports;
}));
return pug_html;
`
var renderer = new Function('', js);
renderer(); // π₯ ReferenceError: require is not defined
So I checked MDN and it says:
Function constructor creates functions which execute in the global scope only.
But it looks fine! Isn't require
in the global scope? ...unless IT IS NOT! π€¦ββοΈ
So I went to check Node.js doc:
These objects are available in all modules.
The following variables may appear to be global but are not.
They exist only in the scope of modules, see the module system documentation:
* __dirname
* __filename
* exports
* module
* require()
OK, today I learned, require
is not global variable. π
In fact each top level JS file, aka module, before executed in Node.js, is first wrapped in a function like below (link):
(function (exports, require, module, __filename, __dirname) {
// module code here
});
which means you can even console.log(arguments)
right at top level. require
lives in the local scope of this wrapper function, aka module scope, not in global scope.
Upvotes: 1