Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/build
diff options
context:
space:
mode:
authorGeoSot <geo.sotis@gmail.com>2021-11-23 18:37:14 +0300
committerGitHub <noreply@github.com>2021-11-23 18:37:14 +0300
commit58ffe2334a94a061afab87c9fd1266445016bca5 (patch)
tree2a59efbf256979542be6ce18435c044b308a2c09 /build
parent1ee058adf5ed5fb5d008ee1567fbf0e34cb82ff0 (diff)
build: read & dynamically resolve `imports` on plugins build (#34509)
Our individual js/dist files are now deduplicated properly thus resulting in a size reduction, which varies from ~25% to ~60% depending on the components used. The average savings are 20% uncompressed and ~15% with gzip. This will mostly benefit cases that more than one component is imported from js/dist. In all other cases it doesn't have any effect. Co-authored-by: XhmikosR <xhmikosr@gmail.com>
Diffstat (limited to 'build')
-rw-r--r--build/build-plugins.js203
1 files changed, 62 insertions, 141 deletions
diff --git a/build/build-plugins.js b/build/build-plugins.js
index 2e16e4f03b..0443447436 100644
--- a/build/build-plugins.js
+++ b/build/build-plugins.js
@@ -11,173 +11,94 @@
const path = require('path')
const rollup = require('rollup')
+const glob = require('glob')
const { babel } = require('@rollup/plugin-babel')
const banner = require('./banner.js')
-const rootPath = path.resolve(__dirname, '../js/dist/')
-const plugins = [
- babel({
- // Only transpile our source code
- exclude: 'node_modules/**',
- // Include the helpers in each file, at most one copy of each
- babelHelpers: 'bundled'
- })
-]
-const bsPlugins = {
- Data: path.resolve(__dirname, '../js/src/dom/data.js'),
- EventHandler: path.resolve(__dirname, '../js/src/dom/event-handler.js'),
- Manipulator: path.resolve(__dirname, '../js/src/dom/manipulator.js'),
- SelectorEngine: path.resolve(__dirname, '../js/src/dom/selector-engine.js'),
- Alert: path.resolve(__dirname, '../js/src/alert.js'),
- Base: path.resolve(__dirname, '../js/src/base-component.js'),
- Button: path.resolve(__dirname, '../js/src/button.js'),
- Carousel: path.resolve(__dirname, '../js/src/carousel.js'),
- Collapse: path.resolve(__dirname, '../js/src/collapse.js'),
- Dropdown: path.resolve(__dirname, '../js/src/dropdown.js'),
- Modal: path.resolve(__dirname, '../js/src/modal.js'),
- Offcanvas: path.resolve(__dirname, '../js/src/offcanvas.js'),
- Popover: path.resolve(__dirname, '../js/src/popover.js'),
- ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'),
- Tab: path.resolve(__dirname, '../js/src/tab.js'),
- Toast: path.resolve(__dirname, '../js/src/toast.js'),
- Tooltip: path.resolve(__dirname, '../js/src/tooltip.js')
-}
-
-const defaultPluginConfig = {
- external: [
- bsPlugins.Data,
- bsPlugins.Base,
- bsPlugins.EventHandler,
- bsPlugins.SelectorEngine
- ],
- globals: {
- [bsPlugins.Data]: 'Data',
- [bsPlugins.Base]: 'Base',
- [bsPlugins.EventHandler]: 'EventHandler',
- [bsPlugins.SelectorEngine]: 'SelectorEngine'
- }
-}
+const srcPath = path.resolve(__dirname, '../js/src/')
+const jsFiles = glob.sync(srcPath + '/**/*.js')
-const getConfigByPluginKey = pluginKey => {
- switch (pluginKey) {
- case 'Alert':
- case 'Offcanvas':
- case 'Tab':
- return defaultPluginConfig
-
- case 'Base':
- case 'Button':
- case 'Carousel':
- case 'Collapse':
- case 'Modal':
- case 'ScrollSpy': {
- const config = Object.assign(defaultPluginConfig)
- config.external.push(bsPlugins.Manipulator)
- config.globals[bsPlugins.Manipulator] = 'Manipulator'
- return config
- }
+// Array which holds the resolved plugins
+const resolvedPlugins = []
- case 'Dropdown':
- case 'Tooltip': {
- const config = Object.assign(defaultPluginConfig)
- config.external.push(bsPlugins.Manipulator, '@popperjs/core')
- config.globals[bsPlugins.Manipulator] = 'Manipulator'
- config.globals['@popperjs/core'] = 'Popper'
- return config
- }
+// Trims the "js" extension and uppercases => first letter, hyphens, backslashes & slashes
+const filenameToEntity = filename => filename.replace('.js', '')
+ .replace(/(?:^|-|\/|\\)[a-z]/g, str => str.slice(-1).toUpperCase())
- case 'Popover':
- return {
- external: [
- bsPlugins.Data,
- bsPlugins.SelectorEngine,
- bsPlugins.Tooltip
- ],
- globals: {
- [bsPlugins.Data]: 'Data',
- [bsPlugins.SelectorEngine]: 'SelectorEngine',
- [bsPlugins.Tooltip]: 'Tooltip'
- }
- }
-
- case 'Toast':
- return {
- external: [
- bsPlugins.Data,
- bsPlugins.Base,
- bsPlugins.EventHandler,
- bsPlugins.Manipulator
- ],
- globals: {
- [bsPlugins.Data]: 'Data',
- [bsPlugins.Base]: 'Base',
- [bsPlugins.EventHandler]: 'EventHandler',
- [bsPlugins.Manipulator]: 'Manipulator'
- }
- }
-
- default:
- return {
- external: []
- }
- }
+for (const file of jsFiles) {
+ resolvedPlugins.push({
+ src: file.replace('.js', ''),
+ dist: file.replace('src', 'dist'),
+ fileName: path.basename(file),
+ className: filenameToEntity(path.basename(file))
+ // safeClassName: filenameToEntity(path.relative(srcPath, file))
+ })
}
-const utilObjects = new Set([
- 'Util',
- 'Sanitizer',
- 'Backdrop'
-])
-
-const domObjects = new Set([
- 'Data',
- 'EventHandler',
- 'Manipulator',
- 'SelectorEngine'
-])
-
const build = async plugin => {
- console.log(`Building ${plugin} plugin...`)
+ const globals = {}
- const { external, globals } = getConfigByPluginKey(plugin)
- const pluginFilename = path.basename(bsPlugins[plugin])
- let pluginPath = rootPath
+ const bundle = await rollup.rollup({
+ input: plugin.src,
+ plugins: [
+ babel({
+ // Only transpile our source code
+ exclude: 'node_modules/**',
+ // Include the helpers in each file, at most one copy of each
+ babelHelpers: 'bundled'
+ })
+ ],
+ external: source => {
+ // Pattern to identify local files
+ const pattern = /^(\.{1,2})\//
+
+ // It's not a local file, e.g a Node.js package
+ if (!pattern.test(source)) {
+ globals[source] = source
+ return true
+ }
- if (utilObjects.has(plugin)) {
- pluginPath = `${rootPath}/util/`
- }
+ const usedPlugin = resolvedPlugins.find(plugin => {
+ return plugin.src.includes(source.replace(pattern, ''))
+ })
- if (domObjects.has(plugin)) {
- pluginPath = `${rootPath}/dom/`
- }
+ if (!usedPlugin) {
+ throw new Error(`Source ${source} is not mapped!`)
+ }
- const bundle = await rollup.rollup({
- input: bsPlugins[plugin],
- plugins,
- external
+ // We can change `Index` with `UtilIndex` etc if we use
+ // `safeClassName` instead of `className` everywhere
+ globals[path.normalize(usedPlugin.src)] = usedPlugin.className
+ return true
+ }
})
await bundle.write({
- banner: banner(pluginFilename),
+ banner: banner(plugin.fileName),
format: 'umd',
- name: plugin,
+ name: plugin.className,
sourcemap: true,
globals,
generatedCode: 'es2015',
- file: path.resolve(__dirname, `${pluginPath}/${pluginFilename}`)
+ file: plugin.dist
})
- console.log(`Building ${plugin} plugin... Done!`)
+ console.log(`Built ${plugin.className}`)
}
-const main = async () => {
+(async () => {
try {
- await Promise.all(Object.keys(bsPlugins).map(plugin => build(plugin)))
+ const basename = path.basename(__filename)
+ const timeLabel = `[${basename}] finished`
+
+ console.log('Building individual plugins...')
+ console.time(timeLabel)
+
+ await Promise.all(Object.values(resolvedPlugins).map(plugin => build(plugin)))
+
+ console.timeEnd(timeLabel)
} catch (error) {
console.error(error)
-
process.exit(1)
}
-}
-
-main()
+})()