question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

CSF story order depends on webpack and breaks with vanilla es module imports

See original GitHub issue

Describe the bug The order of stories within the code of an index.stories.js file (in CSF format) determines the order of the storybook menu.

Consider the following example

// orderedNamedExports.js
export const b = 'BB';
export const a = 'AA';
export const c = 'CC';

// start.js
import('./orderedNamedExports.js').then(module => {
  console.log(Object.keys(module));
});

When loading this file by going through webpack it will result in

// (3) ["b", "a", "c"]

However, when using a browser native es module import the modules will be sorted.

// (3) ["a", "b", "c"]

It is specified in the es module spec https://tc39.es/ecma262/#sec-modulenamespacecreate

  1. Let sortedExports be a new List containing the same values as the list exports where the values are ordered as if an Array of the same values had been sorted using Array.prototype.sort using undefined as comparefn.

There are also part of the official platform tests https://github.com/tc39/test262/blob/master/test/language/module-code/namespace/internals/own-property-keys-sort.js

it sort of all started with this tweet so if you are interested there are more details https://twitter.com/daKmoR/status/1204877164233015297?s=20

As this order determines the menu order it will result in “wrong menus” if you are not using webpack[1] - (and possible also when doing production builds with the upcoming es module flag in webpack v5)

To Reproduce

  1. have a story file like
import { html } from '../../index.js';

export default {
  title: 'Has order Paragraph-Heading',
};

export const paragraph = () =>
  html`
    <p>First Story</p>
  `;

export const heading = () =>
  html`
    <h1>Second Story</h1>
  `;
  1. using webpack results in the following menu
  • Paragraph
  • Heading
  1. using vanilla es module imports results in the following menu
  • Heading
  • Paragraph

Expected behavior Have storybook have the same story order when using webpack and when using es modules.

strawman proposal We could export a special __exportOrder array from within story files. This could be automatically done by a loader.

possible addition for the example above

// 1.
export __exportOrder = ['paragraph', 'heading'];

// 2.
export __orderedExports = [paragraph, heading];

with 1. you would sort the * imports via this array and with 2. you would ignore all other imports and just use this ordered array contain all exports.

Personally I think 2. sounds better

What do you all think?


[1]: > A quick check shows the problem is not limited to webpack; Babel & TypeScript also make no attempt to sort exports. tweet

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:7
  • Comments:14 (14 by maintainers)

github_iconTop GitHub Comments

1reaction
daKmoRcommented, Dec 17, 2019

so I tested this and it works actually really nice 👍

one thing to mention is that the current implementation requires the key and the function… so using a simple array is not good enough => e.g. the simples would be to just use an object then 2 line changes in storybook are all that is needed

// 1.
// code in story files
export const __orderedExports = { heading, card };

// storybook core
const { default: meta, __orderedExports, ...namedExports } = fileExports;
const exports = __orderedExports || namedExports;

if we want an array then it would need to be an array of strings which we later use to create a source ordered object out of the alphabetically ordered exports.

// 2.
// code in story files
export const __storyOrder = ['heading', 'card'];

// storybook core
const { default: meta, __storyOrder, ...namedExports } = fileExports;
const exports = __storyOrder ? createExportsFromOrderAndNames(namedExports, __storyOrder) || namedExports;

function createExportsFromOrderAndNames(namedExports, order) {
  const exports = {};
  order.forEach((exportName => {
    exports[exportName] = namedExports[exportName];
  });
  return exports;
}

imho 1. is good enough 👍 an array seems “cleaner” but not needing to add logic to create a new object out of an array and an object seems overall preferable

sounds good? 🤗

1reaction
shilmancommented, Dec 17, 2019

Works for me! 👍

Slightly cleaner:

const { default: meta, __orderedExports, ...namedExports } = fileExports;
const exports = __orderedExports || rawExports;
Read more comments on GitHub >

github_iconTop Results From Across the Web

Thomas Allmer on Twitter: "TIL an es module import orders ...
TIL an es module import orders your exports alphabetically. ... CSF story order depends on webpack and breaks with vanilla es module imports...
Read more >
Component Story Format (CSF) - Storybook
In CSF, stories and component metadata are defined as ES Modules. Every component story file consists of a required default export and one...
Read more >
@storybook/react-native-server | Yarn - Package Manager
Fast, reliable, and secure dependency management.
Read more >
@open-wc/demoing-storybook - npm
Create documentation/stories within the stories folder. npm run storybook. CLI configuration. name, type, description. stories, string ...
Read more >
Dependencies | umi_cps | npm - Open Source Insights
arrow_right antd. 3.26.16 Notes Relation Licenses Depende... Version 3.26.16 Published April 26, 2020 Description arrow_right father. 2.30.23 Notes Relation Licenses Depende... Version 2.30.23 Published September 15,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found