-
-
Notifications
You must be signed in to change notification settings - Fork 231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for 'umd' and 'amd' formats #924
Comments
I have been wanting to do the same. I am currently trying out the esbuild plugin named
At first sight it appears to work as expected |
I get an error when I specify 'umd' as a format |
Or, to others, is there another way to create a UMD package with tsup ? |
@dhowe My org has been generating our bundles as |
thanks @bo-carey
with what tooling ? |
@dhowe Thankfully our library consumers use ember so they have access to transforming esm -> amd via the ember-cli. Otherwise, there are some small libraries out there to transform it, such as |
The following worked in my case: tsup.config.cjs import { defineConfig } from 'tsup'
import umdWrapper from 'esbuild-plugin-umd-wrapper'
import { dependencies } from './package.json'
import { createUmdWrapper } from './build-plugins/umdWrapperPlugin.cjs'
const externalDependencies = Object.keys(dependencies)
const sdkClientVersion = '1.0.0'
const clientName = `ClientName`
const isDevelopmentMode = process.env._DEV === 'true'
/** @type {import('tsup').Options} */
const baseConfig = {
entry: {
appstore: 'src/index.ts',
},
outDir: 'dist',
outExtension({ format, options }) {
const ext = format === 'esm' ? 'mjs' : 'js'
const outputExtension = options.minify ? `${format}.min.${ext}` : `${format}.${ext}`
return {
js: `.${outputExtension}`,
}
},
platform: 'browser',
format: ['cjs', 'esm'],
noExternal: externalDependencies,
target: ['chrome90', 'edge90', 'firefox90', 'opera98', 'safari15'],
name: '@company/client',
globalName: clientName,
legacyOutput: false,
bundle: true,
esbuildPlugins: [],
banner: { js: `/* Client SDK version ${sdkClientVersion} */\n` },
define: {
__VERSION__: `'${sdkClientVersion}'`,
},
minify: false,
splitting: false,
sourcemap: true,
dts: false,
clean: true,
onSuccess: 'tsc --project tsconfig.build.json --emitDeclarationOnly --declaration',
watch: isDevelopmentMode,
metafile: isDevelopmentMode,
}
export default defineConfig([
{
...baseConfig,
esbuildPlugins: [],
minify: false,
},
{
...baseConfig,
esbuildPlugins: [],
minify: true,
},
{
...baseConfig,
format: ['umd'],
minify: false,
plugins: [createUmdWrapper({ libraryName: clientName, external: [] })],
},
{
...baseConfig,
minify: true,
format: ['umd'],
plugins: [createUmdWrapper({ libraryName: clientName, external: [] })],
},
{
...baseConfig,
entry: {
marketplace: 'src/index.ts',
},
minify: false,
target: 'es5',
format: ['umd'],
outputExtension: {
js: `browser.js`,
},
outDir: 'dist',
esbuildPlugins: [umdWrapper({ libraryName: clientName, external: 'inherit' })],
},
]) umdWrapperPlugin.cjs import * as path from 'node:path'
import * as fs from 'node:fs'
/*
Plugin is based on the `esbuild-plugin-umd-wrapper``, found at:
https://github.com/inqnuam/esbuild-plugin-umd-wrapper
*/
// eslint-disable-next-line no-unused-vars
const createWrapperWithLib = ({ depsKeys, depsValKey, amdLoader, lib, defineDeps, globalDeps, requireDeps }) => {
return `(function (g, f) {
if ("object" == typeof exports && "object" == typeof module) {
module.exports = f(${requireDeps});
} else if ("function" == typeof ${amdLoader} && ${amdLoader}.amd) {
${amdLoader}("${lib}", ${defineDeps}, f);
} else if ("object" == typeof exports) {
exports["${lib}"] = f(${requireDeps});
} else {
g["${lib}"] = f(${globalDeps});
}
}(this, (${depsKeys}) => {
var exports = {};
var module = { exports };\n\n`
}
export const alphabet = [
'__da',
'__db',
'__dc',
'__dd',
'__de',
'__df',
'__dg',
'__dh',
'__di',
'__dj',
'__dk',
'__dl',
'__dm',
'__dn',
'__do',
'__dp',
'__dq',
'__dr',
'__ds',
'__dt',
'__du',
'__dv',
'__dw',
'__dx',
'__dy',
'__dz',
]
function getUmdBanner(opts) {
const external = opts.external ?? []
const defineDeps = external?.length ? `['${external.join("', '")}']` : '[]'
const globalDeps = external?.map(x => `g["${x}"]`).join(', ') ?? ''
const requireDeps = external?.map(x => `require('${x}')`).join(', ') ?? ''
let deps = []
if (external) {
deps = external.map((x, i) => {
return {
key: alphabet[i],
val: x,
}
})
}
const depsKeys = deps.map(x => x.key).join(', ')
const depsValKey = deps.map(x => `"${x.val}": ${x.key}`).join(', ')
const options = {
depsKeys,
depsValKey,
amdLoader: 'define',
defineDeps,
globalDeps,
requireDeps,
lib: opts.libraryName,
}
const result = createWrapperWithLib(options)
return result
}
export const umdFooter = `if (typeof module.exports == "object" && typeof exports == "object") {
var __cp = (to, from, except, desc) => {
if ((from && typeof from === "object") || typeof from === "function") {
for (let key of Object.getOwnPropertyNames(from)) {
if (!Object.prototype.hasOwnProperty.call(to, key) && key !== except)
Object.defineProperty(to, key, {
get: () => from[key],
enumerable: !(desc = Object.getOwnPropertyDescriptor(from, key)) || desc.enumerable,
});
}
}
return to;
};
module.exports = __cp(module.exports, exports);
}
return module.exports;
}))\n\n\n`
export const umdWrapperSetup = build => {
const { initialOptions } = build
const external = initialOptions.external
const content = getUmdBanner(external)
if (initialOptions.footer) {
if (initialOptions.footer.js) {
initialOptions.footer.js += umdFooter
} else {
initialOptions.footer.js = umdFooter
}
} else {
initialOptions.footer = {
js: umdFooter,
}
}
if (initialOptions.banner) {
if (initialOptions.banner.js) {
initialOptions.banner.js += content
} else {
initialOptions.banner.js = content
}
} else {
initialOptions.banner = {
js: content,
}
}
}
export const createUmdWrapper = opts => {
let pluginExternalDependencies = []
return {
name: 'add-umd-wrapper',
esbuildOptions(options) {
options.format = 'cjs'
pluginExternalDependencies = []
return options
},
buildEnd(result) {
try {
result.writtenFiles.forEach(file => {
const filePath = path.join(process.cwd(), file.name)
if (file.name.endsWith('.js')) {
const fileName = path.basename(file.name)
const umdBanner = getUmdBanner({ ...opts, external: pluginExternalDependencies })
// eslint-disable-next-line security/detect-non-literal-fs-filename
const content = fs.readFileSync(filePath, 'utf-8')
const patchedFileContents = content.replace(`//# sourceMappingURL=${fileName}.map`, '')
const scriptContent = `\n\n\n${patchedFileContents}\n\n\n`
const wrappedContent = `${umdBanner}${scriptContent}${umdFooter}\n\n//# sourceMappingURL=${fileName}.map\n`
const newContent = `/* umd */\n${wrappedContent}`
// eslint-disable-next-line security/detect-non-literal-fs-filename
fs.writeFileSync(filePath, newContent, 'utf8')
}
})
} catch (err) {
// eslint-disable-next-line no-console
console.error(err)
}
},
}
} |
thanks @weyert |
Hello! Are there any plans or existing solutions to format as
UMD
orAMD
?Upvote & Fund
The text was updated successfully, but these errors were encountered: