Skip to content

Major version 5.0 ‐ ES6 ESM and TypeScript Support

Ghislain B. edited this page Oct 7, 2024 · 51 revisions

Welcome to the modern world 🌐

This new version is all about modernizing the project (modern toolings and a modern look), it brings a lot of changes:

  • Node 18 is required (since Node 16 is already EOL by a few months already)
  • Migrated to TypeScript build which also provides Types (d.ts)
  • ES6 / ESM support while still providing standalone scripts (IIFE)
  • New Modern Alpine Theme (inspired by Ag-Grid) that can be customized via SASS and/or CSS variables (Classic Theme is also still available)
  • Replaced (removed) all images with a small subset of SVGs that can also be colorized via pure CSS (see SlickGrid Icons)

With this latest version release, we can now say that our journey into modernizing the project is, for the most part, completed (it started with v3 by removing jQueryUI, it was followed by jQuery removal in v4 and today we are modernizing the project in v5). Finally all of that being said, we do not expect any major (aka breaking) changes & versions for the foreseeable future... we're pretty much done!!!

See Migration below for instructions or keep reading for more details about this release.

ES6 / ESM

Bringing ES6/ESM with TypeScript support was the main focus of this release and it also closes our oldest issue #41 while still providing standalone scripts for users who still prefer them. However please note that in order to support this new rewrite, we needed to change the folder structure (all source files were moved to src/ and all builds now exist in the dist/ folder), this also mean that every single users will have to update their script imports to the new dist/[target] folders in order to use SlickGrid. Also note that all users will no longer be able to use any of the core file directly since they are now TypeScript files.

We now use esbuild in order to support multiple build targets and the new folder structure, we now have the following build output targets

  • IIFE to still provide standalone <script> that SlickGrid provided for years (located under dist/browser with ES2018 build target)
  • CJS for CommonJS build for NodeJS legacy importing via require(...) (located under dist/cjs with ES2020 build target)
  • ESM for ES6/ESM support which will give us Tree Shaking support (located under dist/esm with ES2020 build target)

Note I did a lot of research to make sure that we get the smallest possible build sizes for every build formats, for example I did not want to have code that won't be used by the IIFE format but is required by ESM and vice versa (i.e. imports are used by ESM but irrelevant in IIFE). It took me a while to find the best approach, I even asked on SO with this question: esbuild hybrid plugin to bundle multiple files iife and single esm bundle and opened an issue on esbuild as well. I eventually made it all work with an hybrid approach with the smallest footprint possible for each build types, woohoo 🚀

TypeScript

Since we are now using esbuild, it supports TypeScript out of the box and it is also providing us with a few other benefits

  • by using TypeScript we can spot errors early even before publishing any new release when bundling the code (we did actually spot a few small errors in the code)
  • provide TS Types .d.ts (interfaces, enums, types, ...)
  • TypeScript extendable (see below for some examples)
    • we use protected everywhere to make it easily extendable (instead of private)
    • we now also provide TS Generics to optionally define your items interface via SlickGrid<TData> and/or SlickDataView<TData>, which then flows to all SlickGrid/DataView sub-methods

Note if you are using TypeScript and are saving it as a .ts file, then make sure to add types to your columns (i.e.: let columns: Column[]) or else you might get a TypeScript error as displayed in this Stack Overflow. Adding the GridOption type is also a good idea to make sure that you only use valid options.

Note also make sure that your import is from 'slickgrid'; not slickgrid/* since that can also cause issues.

Here's a quick example of how we can now use TypeScript with SlickGrid (see TypeScript Examples Wiki for more details)

// example.ts (TypeScript file)
import { Column, GridOption, SlickDataView, SlickGrid } from 'slickgrid';

let data: any[] = []; // or `data: User[] = [];` with a User interface  then provide it as a Generic to SlickGrid (see below)
let columns: Column[] = [{ id: 'firstName', name: 'First Name', field: 'firstName' }, ...]; // or `Column<User>[]` if you want add column type
let options: GridOption = { enableCellNavigation: true, ... };

let grid = new SlickGrid('#myGrid', data, columns, options);
// let grid = new SlickGrid<User>('#myGrid', data, columns, options); // or with a User provided to SlickGrid as Generic type

// similarly for DataView
let dataView = new SlickDataView({ inlineFilter: true });
// let dataView = new SlickDataView<User>({ inlineFilter: true }); // same Generic can be used as data interface

Styling

We have a new optional Alpine Theme which is now imported in most examples (but not all of them), if you wanted to compare both the classic (previous theme) and the new Alpine Theme, you could just go to the new ESM Example and toggle the 2 themes by using the associated Theme buttons.

Contributions

We welcome any new contributions, for example it shouldn't be too hard to add a dark Alpine theme and a contribution would be more than welcome. Please do remember that this is an Open Source project and most of this work is achieved in our spare time (for free) and so we certainly welcome any contributions but please be respectful.

Migration

Deprecated code

Please note that to align all Menu plugins, we decided to rename all menu item array lists as commandItems, these changes are preferred but the old names will still work for now with console warnings of the deprecations, these warnings will only be removed in a future major version (if it ever happen). The changes are focused on just these 2 plugins:

  • Header Menu
    • renamed items to commandItems
  • Grid Menu
    • renamed customItems to commandItems
    • renamed customTitle to commandTitle

Deprecated code & removed

DataView setAggregators and groupBy methods were marked as deprecated many years ago by the original author and were finally removed them in this release. They were replaced by setGrouping a while ago, so just make sure to use the newer setGrouping method if you haven't already.

We also remove all firebugx code (they are no longer necessary since all browsers now have much improved developer tools).

All images were replaced by SVGs

All images (.gif, .png, ...) were deleted and replaced by a small subset of SVG icons in pure CSS (icons are prefixed with sgi keyword for "Slick Grid Icons") which can also be colorized via CSS (see SlickGrid Icons page).

We used the technique that Anthony Fu, creator of UnoCSS, wrote in his article Reimagine Atomic CSS, this article was very helpful to learn how easy it is to colorize SVG with pure CSS.

Some might ask, why use SVGs instead of perhaps Data URI or something else? You can read this article Probably Don’t Base64 SVG to understand why SVGs are simply better suited and much smaller than images or fonts.

For example, if you were previously using images in DraggableGrouping (or any other plugins), you might want to replace some of the images by the new SlickGrid SVGs by using .sgi CSS classes

const draggableGrouping = new Slick.DraggableGrouping({
-  deleteIconImage:'../images/delete.png', 
-  groupIconImage: '../images/column-grouping.png',
+  deleteIconCssClass: 'sgi sgi-close',
+  groupIconCssClass: 'sgi sgi-drag-vertical'
});

Draggable Grouping

Since we migrated to TypeScript Classes and we no longer use any global variables, then please note that this caused a scoping issue when using the DraggableGrouping plugin, so you will need to add a .bind(...) on the plugin instance to point it to the correct scope.

const draggableGrouping = new Slick.DraggableGrouping();
const gridOptions = {
-   enableColumnReorder: draggableGrouping.getSetupColumnReorder(draggableGrouping)
+   enableColumnReorder: draggableGrouping.getSetupColumnReorder.bind(draggableGrouping)
    createPreHeaderPanel: true,
    showPreHeaderPanel: true,
    preHeaderPanelHeight: 25,
}

Standalone scripts (IIFE)

For users who still want to use standalone <script>, the migration is quite simple and you will simply have to update your script locations and that's about it. Using standalone scripts will keep providing users with independent scripts the same as before (slick.grid.js, plugins/slick.headermenu.js, ...) but from a different location dist/browser/...

Note it is very important that slick.core.js and slick.interaction.js are imported first because core is the script that creates the Slick namespace and slick.interaction is also required by the grid. The order might not have been important in the past, but it is important today so that all 3 build types are supported.

- <script src="slickgrid/slick.core.js"></script>
- <script src="slickgrid/slick.grid.js"></script>
+ <script src="slickgrid/dist/browser/slick.core.js"></script>
+ <script src="slickgrid/dist/browser/slick.interactions.js"></script>
+ <script src="slickgrid/dist/browser/slick.grid.js"></script>

or from a CDN like JsDelivr

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/styles/css/slick-alpine-theme.min.css" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser/slick.core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser/slick.interactions.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser/slick.grid.min.js"></script>

ES6 / ESM (cjs, esm)

By using esbuild we can provide multiple new targets (iife same as before and our new cjs and esm), the last 2 are the new ones for the project which allows us to close our oldest issue #41

Note all core files and plugins are exported with the Slick prefix (e.g. SlickGrid, SlickDataView, SlickColumnPicker, ...) with some exceptions (Aggregators, Editors, Formatters and all enums like ColAutosizeMode, RowSelectionMode, ...)

For a demo, you can take a look at this ESM - Example 4 or our new awesome demo of a Realtime Trading - High Frequency Update dashboard.

- <script src="slickgrid/slick.core.js"></script>
- <script src="slickgrid/slick.grid.js"></script>

+ <script type="module">
+ import {
+   Editors,
+   Formatters,
+   SlickGlobalEditorLock,
+   SlickRowSelectionModel,
+   SlickColumnPicker,
+   SlickDataView,
+   SlickGridPager,
+   SlickGrid,
+   Utils,
+ } from 'slickgrid';

- const dv = new Slick.DataView();
- const grid = new Slick.Grid('#myGrid', dv, columns, options);

// the only difference is the "." which is removed, there's no more Slick namespace
+ const dataView = new SlickDataView();
+ const grid = new SlickGrid('#myGrid', dataView, columns, options);

Note since SortableJS is a hard dependency, you will also need to make sure that you import it and you assign it to the window object (unless you load it through <script>, if so then there's nothing to do). Another way would to be to configure it in your WebPack or Vite config to make it globally available.

+ import Sortable from 'sortablejs';
+ window.Sortable = Sortable;

Styling

With the new SlickGrid Alpine Theme, if you are using it, we needed an extra (but optional) CSS class to identify the grid div container, we opted to use slick-container and even though it is optional, it's probably better to add it to your grids. Again, this extra container CSS class is optional but some of the styling from the new Alpine Theme might not show up correctly without it.

For example, the grid border outline requires this container class to exist for showing the border correctly

- <div id="myGrid" style="width:100%;height:500px;"></div>
+ <div id="myGrid" class="slick-container" style="width:100%;height:500px;"></div>

We now also use CSS flexbox for some part of the grid, like the column headers and that could help in supporting RTL.

CSS / SASS variables

With the new Alpine Theme, we went all in and we also provide both CSS and SASS variables for easy customization, both of them are available under the dist/styles/css or dist/styles/sass folders. For example if you want to use SASS, you can simply import it.

See available SASS variables, also note that the CSS variables are named with the same name except that you simply need to replace the $ prefix with -- prefix (e.g.: for SASS $alpine-font-size and for CSS --alpine-font-size)

Note since CSS Variables offers a fallback when first option is not found, we can use that to our advantage and offer CSS variables as the first choice and SASS variables as a fallback. This mean that if the user is defining both a CSS & SASS variable using the same name, then the CSS variable will win because the SASS is a fallback, however if only a SASS variable is defined then the SASS variable will be used.

with CSS (located under dist/styles/css)
/* optional CSS variables can be used */
:root {
  --alpine-font-size:  14px;
  --alpine-font-color: #111;
}

// import the new Alpine Theme
@import 'slickgrid/dist/styles/css/slick-alpine-theme.css';

// or import the old Classic Theme
@import 'slickgrid/dist/styles/css/slick-default-theme.css';
with SASS (located under dist/styles/sass)
/* change any SASS variables before loading the theme */
$alpine-font-size:  14px;
$alpine-font-color: #111;

// use the new Alpine Theme (currently only SASS theme available)
@import 'slickgrid/dist/styles/sass/slick-alpine-theme.scss';

Other Ports / Platforms Available

Below is a list of other ports which extends from this SlickGrid fork and could be used when developing for specific platforms


TypeScript Extendable

Since we now use TypeScript, we can now provide extra features for free, we now have Types (interfaces, enums, types, ...), Generics and it's also extendable as shown below.

SlickGrid & SlickDataView Generics

We added optional TS Generics to provide the item data context interface on the SlickGrid and/or SlickDataView so that you can call any methods from them and automatically get the associated item interface type for them.

import { SlickGrid, SlickDataView } from 'slickgrid';

interface User {
  firstName: string;
  lastName: string;
  age: number;
}
// Generics on SlickGrid
const grid = new SlickGrid<User>('#myGrid', data, columns, options);
const item = grid.getDataItem(0); // item will be User TS type

// or Generics on SlickDataView
const dataView = new SlickDataView<User>();
const grid = new SlickGrid('#myGrid', dataView, columns, options);
const item = dataView.getItemByIdx(0); // item will be User TS type

The SlickGrid class actually has 3 optional Generics, but you will rarely use the last 2. The 1st Generic is the data item type (as shown above), the 2nd is if you want to extend the Column interface and finally the 3rd and last Generic is if you want to extend the GridOption interface (these extra Generics were mainly added for Slickgrid-Universal usage since that external project also has extra Column & GridOption properties)

Class extends

Since we opted to use protected (instead of private) across all our TypeScript code, it makes it easy to extends (or override) any of these TS classes whenever you wish to customize or add extra methods on any of the SlickGrid classes (not just core files but also Controls and Plugins as well).

// for example let's extend Slick DataView
import { SlickDataView } from 'slickgrid';

class CustomSlickDataView  extends SlickDataView {
  // for example let's add a custom event on the destroy method
  onDestroy = new SlickEvent();

  constructor() {
    super();
  }

  destroy() {
    super.destroy();
    this.onDestroy.notify();
  }
}

// use our new extended DataView
const dv = new CustomSlickDataView();
dv.onDestroy.subscribe(() => console.log('DataView was destroyed'));

Final Note

That's it, enjoy the lib and feel free to contribute to the project. If you encounter any problems, create a new issue or a Discussion. Please remember to keep Questions on Stack Overflow, cheers ⭐🍺🚀

Quick Survey ✨

We made a quick little poll for fun, it would be nice to hear from you, thanks for taking the time to participate and tell us what you like. Cheers

What do you think was the most exciting change(s) for you?

Clone this wiki locally