mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Ship MapView as the tabler-map.js add-on bundle
- tabler.js is back to its size before the maps
This commit is contained in:
1 parent
d460fb47da
commit
409482d5db
13 files changed
+73
-21
No files matched your search
@@ -7,14 +7,17 @@ description: >-
|
||||
|
||||
# The framework JavaScript
|
||||
|
||||
`core/js` builds two shipped bundles. Everything here is public API and is bound by a size budget.
|
||||
`core/js` builds three shipped bundles. Everything here is public API and is bound by a size budget.
|
||||
|
||||
## 1. Two entry points
|
||||
## 1. Three entry points
|
||||
|
||||
| Entry | Ships as | Holds |
|
||||
| -------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| `js/tabler.ts` | `tabler.js` / `.esm.js` (+ `.min`) | plugin initialisers, the Bootstrap components, the `tabler` helper namespace |
|
||||
| `js/tabler-theme.ts` | `tabler-theme.js` (+ variants) | the colour-mode/theme switcher only |
|
||||
| `js/tabler-map.ts` | `tabler-map.js` (+ variants) | the `MapView` component, as an add-on that extends the `tabler` global |
|
||||
|
||||
`tabler-map.js` is loaded after `tabler.js`, and only on pages with a map: a component that few pages use goes in an add-on bundle like this one, not in `tabler.js`. Its UMD build uses `extend` (`core/.build/vite.config.mts`), so it adds its exports to the existing `tabler` global.
|
||||
|
||||
`tabler-theme.js` is loaded right after `<body>` and **not deferred**, so the chosen theme applies before the first paint. It stays tiny on purpose (bundlewatch: 1 kB raw, 800 B minified) — do not add anything to it that is not needed before paint.
|
||||
|
||||
|
||||
@@ -9,20 +9,26 @@ interface CreateViteConfigOptions {
|
||||
outDir: string
|
||||
banner?: string
|
||||
minify?: boolean | 'esbuild'
|
||||
/** UMD only: add the exports to an existing global of the same name instead of replacing it */
|
||||
extend?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vite configuration for building libraries
|
||||
*/
|
||||
export function createViteConfig({ entry, name, fileName, formats, outDir, banner, minify = false }: CreateViteConfigOptions): UserConfig {
|
||||
export function createViteConfig({ entry, name, fileName, formats, outDir, banner, minify = false, extend = false }: CreateViteConfigOptions): UserConfig {
|
||||
// Vite 8 (Rolldown) always emits const bindings and no longer accepts the
|
||||
// Rollup-only generatedCode.constBindings option
|
||||
const rollupOutput: { banner?: string } = {}
|
||||
const rollupOutput: { banner?: string; extend?: boolean } = {}
|
||||
|
||||
if (banner) {
|
||||
rollupOutput.banner = banner
|
||||
}
|
||||
|
||||
if (extend) {
|
||||
rollupOutput.extend = true
|
||||
}
|
||||
|
||||
const config: UserConfig = {
|
||||
// Library builds: never copy <root>/public into outDir (see copy-assets.ts).
|
||||
publicDir: false,
|
||||
|
||||
@@ -8,7 +8,10 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const baseName = process.env.BASE_NAME || 'tabler'
|
||||
const entryFile = baseName
|
||||
const libraryName = baseName
|
||||
// `tabler-map` is an add-on to the main bundle: its UMD build extends the
|
||||
// `tabler` global instead of creating one of its own.
|
||||
const isAddon = baseName === 'tabler-map'
|
||||
const libraryName = isAddon ? 'tabler' : baseName
|
||||
|
||||
const bannerText = getBanner()
|
||||
|
||||
@@ -26,4 +29,5 @@ export default createViteConfig({
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText,
|
||||
minify: false,
|
||||
extend: isAddon,
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
// The map component ships as its own bundle, so pages without a map do not
|
||||
// carry it. Load it after `tabler.js`: the UMD build adds `MapView` to the
|
||||
// `tabler` global.
|
||||
import './src/map'
|
||||
|
||||
export { default as MapView } from './src/map'
|
||||
@@ -4,7 +4,6 @@ import './src/confetti'
|
||||
import './src/countup'
|
||||
import './src/datepicker'
|
||||
import './src/input-mask'
|
||||
import './src/map'
|
||||
import './src/dropdown'
|
||||
import './src/sidebar'
|
||||
import './src/tooltip'
|
||||
@@ -27,7 +26,6 @@ export { default as Confetti } from './src/confetti'
|
||||
export { default as CountUp } from './src/countup'
|
||||
export { default as Datepicker } from './src/datepicker'
|
||||
export { default as InputMask } from './src/input-mask'
|
||||
export { default as MapView } from './src/map'
|
||||
export { default as OtpInput } from './src/otp-input'
|
||||
export { default as Sortable } from './src/sortable'
|
||||
export { default as Sparkline } from './src/sparkline'
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
"maplibre-gl": {
|
||||
"npm": "maplibre-gl",
|
||||
"module": { "file": "dist/maplibre-gl.mjs", "global": "maplibregl" },
|
||||
"addon": "tabler-map",
|
||||
"css": ["dist/maplibre-gl.css"],
|
||||
"extra": ["dist/maplibre-gl.mjs", "dist/maplibre-gl-shared.mjs", "dist/maplibre-gl-worker.mjs"]
|
||||
},
|
||||
|
||||
+24
-6
@@ -17,12 +17,14 @@
|
||||
"lint:scss:vars": "find-unused-sass-variables scss/ --ignoreFiles scss/_variables-deprecated.scss",
|
||||
"js": "pnpm run js:build && pnpm run js:min && pnpm run js:types",
|
||||
"js:types": "tsc -p tsconfig.types.json",
|
||||
"js:build": "concurrently \"pnpm run js:build:standalone\" \"pnpm run js:build:theme\"",
|
||||
"js:build": "concurrently \"pnpm run js:build:standalone\" \"pnpm run js:build:theme\" \"pnpm run js:build:map\"",
|
||||
"js:build:theme": "cross-env BASE_NAME=tabler-theme vite build --config .build/vite.config.mts",
|
||||
"js:build:map": "cross-env BASE_NAME=tabler-map vite build --config .build/vite.config.mts",
|
||||
"js:build:standalone": "cross-env BASE_NAME=tabler vite build --config .build/vite.config.mts",
|
||||
"js:min": "concurrently \"pnpm run js:min:standalone\" \"pnpm run js:min:theme\"",
|
||||
"js:min": "concurrently \"pnpm run js:min:standalone\" \"pnpm run js:min:theme\" \"pnpm run js:min:map\"",
|
||||
"js:min:standalone": "concurrently \"terser dist/js/tabler.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler.js.map,filename=dist/js/tabler.min.js.map,url=tabler.min.js.map\\\" -o dist/js/tabler.min.js\" \"terser dist/js/tabler.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler.esm.js.map,filename=dist/js/tabler.esm.min.js.map,url=tabler.esm.min.js.map\\\" -o dist/js/tabler.esm.min.js\"",
|
||||
"js:min:theme": "concurrently \"terser dist/js/tabler-theme.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-theme.js.map,filename=dist/js/tabler-theme.min.js.map,url=tabler-theme.min.js.map\\\" -o dist/js/tabler-theme.min.js\" \"terser dist/js/tabler-theme.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-theme.esm.js.map,filename=dist/js/tabler-theme.esm.min.js.map,url=tabler-theme.esm.min.js.map\\\" -o dist/js/tabler-theme.esm.min.js\"",
|
||||
"js:min:map": "concurrently \"terser dist/js/tabler-map.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-map.js.map,filename=dist/js/tabler-map.min.js.map,url=tabler-map.min.js.map\\\" -o dist/js/tabler-map.min.js\" \"terser dist/js/tabler-map.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-map.esm.js.map,filename=dist/js/tabler-map.esm.min.js.map,url=tabler-map.esm.min.js.map\\\" -o dist/js/tabler-map.esm.min.js\"",
|
||||
"copy": "concurrently \"pnpm run copy:img\" \"pnpm run copy:libs\"",
|
||||
"copy:img": "tsx .build/copy-img.ts",
|
||||
"copy:libs": "tsx .build/copy-libs.ts",
|
||||
@@ -212,19 +214,35 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.js",
|
||||
"maxSize": "61 kB"
|
||||
"maxSize": "59 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.min.js",
|
||||
"maxSize": "41 kB"
|
||||
"maxSize": "40 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.esm.js",
|
||||
"maxSize": "61 kB"
|
||||
"maxSize": "59 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.esm.min.js",
|
||||
"maxSize": "41 kB"
|
||||
"maxSize": "40 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-map.js",
|
||||
"maxSize": "10 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-map.esm.js",
|
||||
"maxSize": "10 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-map.min.js",
|
||||
"maxSize": "7 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-map.esm.min.js",
|
||||
"maxSize": "7 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-theme.js",
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"rootDir": "js",
|
||||
"outDir": "dist/types"
|
||||
},
|
||||
"include": ["js/tabler.ts", "js/tabler-theme.ts", "js/src/**/*"]
|
||||
"include": ["js/tabler.ts", "js/tabler-theme.ts", "js/tabler-map.ts", "js/src/**/*"]
|
||||
}
|
||||
@@ -61,12 +61,15 @@ MapLibre GL JS is published as an ES module. Tabler uses version 6. Load the sty
|
||||
// The map component looks for the library here
|
||||
window.maplibregl = maplibregl
|
||||
</script>
|
||||
<script src="${site.cdnUrl}/dist/js/tabler.min.js" defer></script>`}
|
||||
<script src="${site.cdnUrl}/dist/js/tabler.min.js" defer></script>
|
||||
<script src="${site.cdnUrl}/dist/js/tabler-map.min.js" defer></script>`}
|
||||
/>
|
||||
|
||||
The map component is not part of `tabler.js`. It ships as a small add-on, `tabler-map.js`, so pages without a map do not carry it. Load it after `tabler.js`; it adds `MapView` to the `tabler` object.
|
||||
|
||||
The library loads two more files from the same folder, `maplibre-gl-shared.mjs` and `maplibre-gl-worker.mjs`, so keep the three together when you host them yourself.
|
||||
|
||||
With a bundler, install the package and set the global before you import Tabler:
|
||||
With a bundler, install the package, set the global, and then import the add-on:
|
||||
|
||||
```bash
|
||||
npm install maplibre-gl
|
||||
@@ -77,8 +80,12 @@ import * as maplibregl from 'maplibre-gl'
|
||||
import 'maplibre-gl/dist/maplibre-gl.css'
|
||||
|
||||
window.maplibregl = maplibregl
|
||||
|
||||
const { MapView } = await import('@tabler/core/dist/js/tabler-map.esm.js')
|
||||
```
|
||||
|
||||
The add-on is imported after the global is set, because it turns the map elements on the page into maps as soon as it loads.
|
||||
|
||||
<Danger title="Use version 6.4.1 or newer">
|
||||
Older versions, including all of version 5, have a known security issue in the code that cleans the attribution text.
|
||||
</Danger>
|
||||
@@ -316,7 +323,7 @@ Live versions of a route, an area, clusters, a bubble map, a globe with arcs and
|
||||
|
||||
### Via data attributes
|
||||
|
||||
An element with `data-bs-toggle="map"` becomes a map when the Tabler script loads:
|
||||
An element with `data-bs-toggle="map"` becomes a map when the `tabler-map.js` script loads:
|
||||
|
||||
<CodeDocs name="map-init" file="core/js/src/map.ts" />
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ const editFilePath =
|
||||
|
||||
// docs-libs for this page. In dev, file names stay unchanged
|
||||
// (e.g. dist/plyr.min.js keeps .min).
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string } };
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string };
|
||||
const libEntries = Object.entries(libs as Record<string, Lib>);
|
||||
const libUrl = (lib: Lib, file: string) =>
|
||||
isExternal(file)
|
||||
@@ -151,6 +151,7 @@ const libUrl = (lib: Lib, file: string) =>
|
||||
const docsLibCss = libEntries
|
||||
.filter(([name]) => docsLibs.includes(name))
|
||||
.flatMap(([, lib]) => (lib.css ?? []).map((file) => libUrl(lib, file)));
|
||||
const docsLibAddons = libEntries.filter(([name]) => docsLibs.includes(name)).flatMap(([, lib]) => (lib.addon ? [lib.addon] : []));
|
||||
const docsLibModules = libEntries
|
||||
.filter(([name]) => docsLibs.includes(name))
|
||||
.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libUrl(lib, lib.module.file)}'; window.${lib.module.global} = lib`] : []));
|
||||
@@ -525,6 +526,7 @@ const relatedPages = await Promise.all(
|
||||
|
||||
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
||||
<script is:inline src="/dist/js/tabler.js" defer></script>
|
||||
{docsLibAddons.map((addon) => <script is:inline src={`/dist/js/${addon}.js`} defer />)}
|
||||
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
||||
|
||||
<PageScripts />
|
||||
|
||||
@@ -73,12 +73,13 @@ const themeAttributes = themeDataAttributes({ ...theme, 'navbar-position': navba
|
||||
// whatever core's own watcher last emitted, which is unminified.
|
||||
const min = import.meta.env.DEV ? '' : '.min'
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string } }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string }
|
||||
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
||||
const libHref = (lib: Lib, file: string) => `/dist/libs/${lib.npm}/${file}`
|
||||
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
||||
const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
// ES-module-only libraries: imported in a module script and exposed as a global (see BaseLayout)
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libHref(lib, lib.module.file)}'; window.${lib.module.global} = lib`] : []))
|
||||
---
|
||||
|
||||
@@ -182,6 +183,7 @@ const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import *
|
||||
{libJsFiles.map((src) => <script is:inline src={src} defer />)}
|
||||
{libModules.map((code) => <Fragment set:html={`<script type="module">${code}</script>`} />)}
|
||||
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`/dist/js/${addon}${min}.js`} defer />)}
|
||||
|
||||
<PageScripts />
|
||||
|
||||
|
||||
@@ -45,12 +45,13 @@ const rtlSuffix = rtl ? '.rtl' : ''
|
||||
// build instead of hardcoding one variant.
|
||||
const min = import.meta.env.DEV ? '' : '.min'
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string } }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string }
|
||||
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
||||
const libHref = (lib: Lib, file: string) => `/dist/libs/${lib.npm}/${file}`
|
||||
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
||||
const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
// ES-module-only libraries: imported in a module script and exposed as a global (see BaseLayout)
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libHref(lib, lib.module.file)}'; window.${lib.module.global} = lib`] : []))
|
||||
---
|
||||
|
||||
@@ -173,6 +174,7 @@ const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import *
|
||||
{libJsFiles.map((src) => <script is:inline src={src} defer />)}
|
||||
{libModules.map((code) => <Fragment set:html={`<script type="module">${code}</script>`} />)}
|
||||
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`/dist/js/${addon}${min}.js`} defer />)}
|
||||
|
||||
<!-- components that render via CaptureScript (e.g. Chart) queue their init script
|
||||
into shared/lib/page-scripts instead of inlining it where used; this drains it. -->
|
||||
|
||||
@@ -39,7 +39,7 @@ const isProduction = process.env.VERCEL_ENV === 'production'
|
||||
// RTL swaps tabler/plugin stylesheets for their .rtl.css variants (demo stays LTR)
|
||||
const rtlSuffix = rtl ? '.rtl' : ''
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; head?: boolean; module?: { file: string; global: string } }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; head?: boolean; module?: { file: string; global: string }; addon?: string }
|
||||
const unknownLibs = pageLibs.filter((name) => !(name in libs))
|
||||
if (unknownLibs.length > 0) {
|
||||
throw new Error(`BaseLayout: unknown pageLibs ${unknownLibs.map((name) => `"${name}"`).join(', ')} — use a key from core/libs.json`)
|
||||
@@ -52,6 +52,8 @@ const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((fil
|
||||
// handed to the classic page scripts as a global. Module scripts are deferred,
|
||||
// so the global is set before DOMContentLoaded.
|
||||
const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libHref(lib, lib.module.file)}'\n window.${lib.module.global} = lib`] : []))
|
||||
// Tabler add-on bundles (dist/js) that a library needs, loaded after tabler.js
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
const libJsFiles = (head: boolean) => pageLibEntries.filter(([, lib]) => Boolean(lib.head) === head).flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
---
|
||||
|
||||
@@ -137,6 +139,7 @@ const libJsFiles = (head: boolean) => pageLibEntries.filter(([, lib]) => Boolean
|
||||
|
||||
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
||||
<script is:inline src={`${base}/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`${base}/dist/js/${addon}${min}.js`} defer />)}
|
||||
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
||||
|
||||
<PageScripts />
|
||||
|
||||
Reference in new issue
Block a user