2019-09-13 13:49:11 +02:00
|
|
|
import path from "path"
|
|
|
|
|
|
|
|
|
|
// These are the dependencies that must be provided for the module loader systemjs
|
|
|
|
|
export const dependencyMap = {
|
2021-05-07 09:28:13 +02:00
|
|
|
"mithril": path.normalize("./libs/mithril.js"),
|
2021-12-23 14:03:23 +01:00
|
|
|
"mithril/stream": path.normalize("./libs/stream.js"),
|
2021-05-07 09:28:13 +02:00
|
|
|
"squire-rte": path.normalize("./libs/squire-raw.js"),
|
|
|
|
|
"dompurify": path.normalize("./libs/purify.js"),
|
2022-01-14 11:56:22 +01:00
|
|
|
"qrcode-svg": path.normalize("./libs/qrcode.js"),
|
2021-05-07 09:28:13 +02:00
|
|
|
"jszip": path.normalize("./libs/jszip.js"),
|
|
|
|
|
"luxon": path.normalize("./libs/luxon.js"),
|
2021-12-23 14:03:23 +01:00
|
|
|
"linkifyjs": path.normalize("./libs/linkify.js"),
|
|
|
|
|
"linkifyjs/html": path.normalize("./libs/linkify-html.js"),
|
2022-01-12 14:43:01 +01:00
|
|
|
"cborg": path.normalize("./libs/cborg.js")
|
2019-09-13 13:49:11 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-12 11:29:23 +01:00
|
|
|
/**
|
|
|
|
|
* These are the definitions of chunks with static dependencies. Key is the chunk and values are dependencies to other chunks
|
|
|
|
|
*/
|
2021-02-15 17:39:53 +01:00
|
|
|
export const allowedImports = {
|
|
|
|
|
"polyfill-helpers": [],
|
|
|
|
|
"common-min": ["polyfill-helpers"],
|
|
|
|
|
"boot": ["polyfill-helpers", "common-min"],
|
|
|
|
|
"common": ["polyfill-helpers", "common-min"],
|
|
|
|
|
"gui-base": ["polyfill-helpers", "common-min", "common", "boot"],
|
|
|
|
|
"main": ["polyfill-helpers", "common-min", "common", "boot", "gui-base"],
|
|
|
|
|
"sanitizer": ["polyfill-helpers", "common-min", "common", "boot", "gui-base"],
|
2021-02-26 14:59:25 +01:00
|
|
|
"date": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "sharing"],
|
2021-02-15 17:39:53 +01:00
|
|
|
"mail-view": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main"],
|
2021-02-26 14:59:25 +01:00
|
|
|
"mail-editor": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "mail-view", "sanitizer", "sharing"],
|
2021-02-15 17:39:53 +01:00
|
|
|
"search": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "mail-view", "contacts", "date"],
|
|
|
|
|
// ContactMergeView needs HtmlEditor even though ContactEditor doesn't?
|
|
|
|
|
"contacts": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "mail-view", "date", "mail-editor"],
|
2021-02-26 14:59:25 +01:00
|
|
|
"calendar-view": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "date", "sharing"],
|
2021-02-15 17:39:53 +01:00
|
|
|
"login": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main",],
|
|
|
|
|
"worker": ["polyfill-helpers", "common-min", "common", "native-common", "native-worker"],
|
|
|
|
|
"settings": [
|
|
|
|
|
"polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "contacts", "sanitizer", "mail-editor", "mail-view", "date",
|
2021-02-26 14:59:25 +01:00
|
|
|
"login", "sharing"
|
2021-02-15 17:39:53 +01:00
|
|
|
],
|
|
|
|
|
"ui-extra": [
|
|
|
|
|
"polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "settings", "contacts", "sanitizer", "login", "mail-editor"
|
|
|
|
|
],
|
2021-02-26 14:59:25 +01:00
|
|
|
"sharing": [
|
|
|
|
|
"polyfill-helpers", "common-min", "common", "boot", "gui-base", "main"
|
|
|
|
|
],
|
2021-02-15 17:39:53 +01:00
|
|
|
"native-common": ["polyfill-helpers", "common-min", "common"],
|
|
|
|
|
"native-main": ["polyfill-helpers", "common-min", "common", "boot", "gui-base", "main", "native-common", "login"],
|
|
|
|
|
"native-worker": ["polyfill-helpers", "common-min", "common"],
|
|
|
|
|
"jszip": ["polyfill-helpers"]
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 13:49:11 +02:00
|
|
|
export function resolveLibs(baseDir = ".") {
|
|
|
|
|
return {
|
|
|
|
|
name: "resolve-libs",
|
|
|
|
|
resolveId(source) {
|
|
|
|
|
const resolved = dependencyMap[source]
|
|
|
|
|
return resolved && path.join(baseDir, resolved)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-12 11:29:23 +01:00
|
|
|
/**
|
|
|
|
|
* Returns the chunk name for the given moduleId which is usually the file path.
|
|
|
|
|
* @param moduleId Rollup moduleId usually the file path.
|
|
|
|
|
* @param getModuleInfo Helper function to get information about the ES module.
|
|
|
|
|
* @returns {string} Chunk name
|
|
|
|
|
*/
|
|
|
|
|
export function getChunkName(moduleId, {getModuleInfo}) {
|
2021-02-15 17:39:53 +01:00
|
|
|
// See HACKING.md for rules
|
2021-11-04 14:05:23 +01:00
|
|
|
const moduleInfo = getModuleInfo(moduleId)
|
|
|
|
|
const code = moduleInfo.code
|
2022-01-07 15:58:30 +01:00
|
|
|
if (code == null) {
|
|
|
|
|
console.log("SYNTHETIC MODULE??", moduleId)
|
|
|
|
|
}
|
2021-11-04 14:05:23 +01:00
|
|
|
if (
|
|
|
|
|
code.includes("@bundleInto:common-min")
|
|
|
|
|
|| moduleId.includes(path.normalize("libs/stream"))
|
|
|
|
|
|| moduleId.includes(path.normalize("packages/tutanota-utils"))
|
|
|
|
|
) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "common-min"
|
|
|
|
|
} else if (code.includes("assertMainOrNodeBoot") ||
|
2021-05-07 09:28:13 +02:00
|
|
|
moduleId.includes(path.normalize("libs/mithril")) ||
|
2022-01-07 15:58:30 +01:00
|
|
|
moduleId.includes(path.normalize("src/app.ts")) ||
|
2021-02-15 17:39:53 +01:00
|
|
|
code.includes("@bundleInto:boot")
|
|
|
|
|
) {
|
|
|
|
|
// everything marked as assertMainOrNodeBoot goes into boot bundle right now
|
|
|
|
|
// (which is getting merged into app.js)
|
|
|
|
|
return "boot"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/gui/date")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/misc/DateParser")) ||
|
2021-03-12 11:29:23 +01:00
|
|
|
moduleId.includes("luxon") ||
|
2021-05-07 09:28:13 +02:00
|
|
|
moduleId.includes(path.normalize("src/calendar/date")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/calendar/export"))
|
2021-02-15 17:39:53 +01:00
|
|
|
) {
|
|
|
|
|
// luxon and everything that depends on it goes into date bundle
|
|
|
|
|
return "date"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/misc/HtmlSanitizer")) || moduleId.includes(path.normalize("libs/purify"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "sanitizer"
|
2022-05-16 15:44:58 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/gui/base"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
// these gui elements are used from everywhere
|
|
|
|
|
return "gui-base"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/native/main")) || moduleId.includes("SearchInPageOverlay")) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "native-main"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/mail/editor")) ||
|
2021-03-12 11:29:23 +01:00
|
|
|
moduleId.includes("squire") ||
|
2021-05-07 09:28:13 +02:00
|
|
|
moduleId.includes(path.normalize("src/gui/editor")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/mail/signature")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/templates")) ||
|
2021-05-27 15:14:41 +02:00
|
|
|
moduleId.includes(path.normalize("src/knowledgebase")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/mail/press"))
|
2021-02-15 17:39:53 +01:00
|
|
|
) {
|
|
|
|
|
// squire is most often used with mail editor and they are both not too big so we merge them
|
|
|
|
|
return "mail-editor"
|
|
|
|
|
} else if (
|
2021-05-07 09:28:13 +02:00
|
|
|
moduleId.includes(path.normalize("src/api/main")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/mail/model")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/contacts/model")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/calendar/model")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/search/model")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/misc/ErrorHandlerImpl")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/misc")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/file")) ||
|
2022-02-08 15:21:18 +01:00
|
|
|
moduleId.includes(path.normalize("src/gui")) ||
|
|
|
|
|
moduleId.includes(path.normalize("packages/tutanota-usagetests"))
|
2021-02-15 17:39:53 +01:00
|
|
|
) {
|
|
|
|
|
// Things which we always need for main thread anyway, at least currently
|
|
|
|
|
return "main"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/mail/view")) || moduleId.includes(path.normalize("src/mail/export"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "mail-view"
|
2021-05-28 16:46:29 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/native/worker"))
|
|
|
|
|
|| moduleId.includes(path.normalize("libs/linkify"))
|
|
|
|
|
|| moduleId.includes(path.normalize("libs/linkify-html"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "worker"
|
2022-01-07 15:58:30 +01:00
|
|
|
} else if (moduleId.includes(path.normalize("src/native/common"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "native-common"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/search"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "search"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/calendar/view"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "calendar-view"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/contacts"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "contacts"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/login/recover"))
|
|
|
|
|
|| moduleId.includes(path.normalize("src/support"))
|
|
|
|
|
|| moduleId.includes(path.normalize("src/login/contactform"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
// Collection of small UI components which are used not too often
|
|
|
|
|
// Perhaps contact form should be separate
|
|
|
|
|
// Recover things depends on HtmlEditor which we don't want to load on each login
|
|
|
|
|
return "ui-extra"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/login"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "login"
|
2022-01-07 15:58:30 +01:00
|
|
|
} else if (moduleId.includes(path.normalize("src/api/common"))
|
|
|
|
|
|| moduleId.includes(path.normalize("src/api/entities"))
|
|
|
|
|
|| moduleId.includes(path.normalize("src/desktop/config/ConfigKeys"))
|
2022-01-12 14:43:01 +01:00
|
|
|
|| moduleId.includes("cborg")
|
2022-03-24 11:55:54 +01:00
|
|
|
|| moduleId.includes(path.normalize("src/offline"))
|
2022-01-07 15:58:30 +01:00
|
|
|
) {
|
2021-02-15 17:39:53 +01:00
|
|
|
// things that are used in both worker and client
|
|
|
|
|
// entities could be separate in theory but in practice they are anyway
|
|
|
|
|
return "common"
|
2022-01-07 15:58:30 +01:00
|
|
|
} else if (moduleId.includes("rollupPluginBabelHelpers") || moduleId.includes("commonjsHelpers") || moduleId.includes("tslib")) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "polyfill-helpers"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/settings")) ||
|
|
|
|
|
moduleId.includes(path.normalize("src/subscription")) ||
|
|
|
|
|
moduleId.includes(path.normalize("libs/qrcode"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
// subscription and settings depend on each other right now.
|
|
|
|
|
// subscription is also a kitchen sink with signup, utils and views, we should break it up
|
|
|
|
|
return "settings"
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("src/sharing"))) {
|
2021-02-26 14:59:25 +01:00
|
|
|
return "sharing"
|
2021-11-19 14:48:33 +01:00
|
|
|
} else if (moduleId.includes(path.normalize("src/api/worker"))
|
|
|
|
|
|| moduleId.includes(path.normalize("packages/tutanota-crypto"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "worker" // avoid that crypto stuff is only put into native
|
2021-05-07 09:28:13 +02:00
|
|
|
} else if (moduleId.includes(path.normalize("libs/jszip"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
return "jszip"
|
|
|
|
|
} else {
|
|
|
|
|
// Put all translations into "translation-code"
|
|
|
|
|
// Almost like in Rollup example: https://rollupjs.org/guide/en/#outputmanualchunks
|
|
|
|
|
// This groups chunks but does not rename them for some reason so we do chunkFileNames below
|
2022-01-07 15:58:30 +01:00
|
|
|
const match = /.*[\\|\/]translations[\\|\/](\w+)+\.ts/.exec(moduleId)
|
2021-02-15 17:39:53 +01:00
|
|
|
if (match) {
|
|
|
|
|
const language = match[1]
|
|
|
|
|
return "translation-" + language
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-12 11:29:23 +01:00
|
|
|
/**
|
|
|
|
|
* Creates a plugin which checks that all imports satisfy the rules that are defined in {@link allowedImports}.
|
|
|
|
|
*/
|
|
|
|
|
export function bundleDependencyCheckPlugin() {
|
2021-02-15 17:39:53 +01:00
|
|
|
return {
|
2021-03-12 11:29:23 +01:00
|
|
|
name: "bundle-dependency-check",
|
2021-02-15 17:39:53 +01:00
|
|
|
generateBundle(outOpts, bundle) {
|
2021-03-12 11:29:23 +01:00
|
|
|
// retrieves getModule function from plugin context.
|
2021-02-15 17:39:53 +01:00
|
|
|
const getModuleInfo = this.getModuleInfo.bind(this)
|
|
|
|
|
|
2021-03-12 11:29:23 +01:00
|
|
|
for (const chunk of Object.values(bundle)) {
|
2022-02-18 09:12:05 +01:00
|
|
|
if (!chunk || !chunk.modules) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-03-12 11:29:23 +01:00
|
|
|
for (const moduleId of Object.keys(chunk.modules)) {
|
|
|
|
|
// Its a translation file and they are in their own chunks. We can skip further checks.
|
2021-05-07 09:28:13 +02:00
|
|
|
if (moduleId.includes(path.normalize("src/translations"))) {
|
2021-02-15 17:39:53 +01:00
|
|
|
continue
|
|
|
|
|
}
|
2021-03-12 11:29:23 +01:00
|
|
|
const ownChunk = getChunkName(moduleId, {getModuleInfo})
|
2021-02-15 17:39:53 +01:00
|
|
|
if (!allowedImports[ownChunk]) {
|
2021-03-12 11:29:23 +01:00
|
|
|
throw new Error(`Unknown chunk: ${ownChunk} of ${moduleId}`)
|
2021-02-15 17:39:53 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-12 11:29:23 +01:00
|
|
|
for (const importedId of getModuleInfo(moduleId).importedIds) {
|
|
|
|
|
// static dependencies on translation files are not allowed
|
2021-05-07 09:28:13 +02:00
|
|
|
if (importedId.includes(path.normalize("src/translations"))) {
|
2021-03-12 11:29:23 +01:00
|
|
|
throw new Error(`Static dependency of ${importedId} is not allowed from ${moduleId}`)
|
2021-02-15 17:39:53 +01:00
|
|
|
}
|
2021-03-12 11:29:23 +01:00
|
|
|
const importedChunk = getChunkName(importedId, {getModuleInfo})
|
2021-02-15 17:39:53 +01:00
|
|
|
if (!allowedImports[importedChunk]) {
|
2021-03-12 11:29:23 +01:00
|
|
|
throw new Error(`Unknown chunk: ${importedChunk} of ${importedId}`)
|
2021-02-15 17:39:53 +01:00
|
|
|
}
|
|
|
|
|
if (ownChunk !== importedChunk && !allowedImports[ownChunk].includes(importedChunk)) {
|
2021-03-12 11:29:23 +01:00
|
|
|
throw new Error(`${moduleId} (from ${ownChunk}) imports ${importedId} (from ${importedChunk}) which is not allowed`)
|
2021-02-15 17:39:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-07 15:58:30 +01:00
|
|
|
}
|