{"id":20349233,"url":"https://github.com/strapi/javascript","last_synced_at":"2026-03-19T15:26:02.855Z","repository":{"id":65980247,"uuid":"577370982","full_name":"strapi/javascript","owner":"strapi","description":"Strapi Javascript Style Guide","archived":false,"fork":false,"pushed_at":"2022-12-13T15:05:55.000Z","size":3,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":8,"default_branch":"main","last_synced_at":"2026-02-11T00:36:57.046Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strapi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-12T15:34:03.000Z","updated_at":"2024-07-16T23:42:57.000Z","dependencies_parsed_at":"2023-02-19T19:31:25.176Z","dependency_job_id":null,"html_url":"https://github.com/strapi/javascript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/strapi/javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strapi%2Fjavascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strapi%2Fjavascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strapi%2Fjavascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strapi%2Fjavascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strapi","download_url":"https://codeload.github.com/strapi/javascript/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strapi%2Fjavascript/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29567344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T00:47:08.760Z","status":"online","status_checked_at":"2026-02-18T02:00:09.468Z","response_time":162,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T22:24:46.364Z","updated_at":"2026-02-18T03:31:33.941Z","avatar_url":"https://github.com/strapi.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Strapi Javascript Style Guide\n\n## Table of Contents\n\n1. [Classes](#classes)\n2. [Modules \u0026 Constructors](#modules-and-constructors)\n\n## Classes\n\n**Airbnb ref**: https://github.com/airbnb/javascript#classes--constructors\n\n### Prefer object instead of class instance for modules\n\n**Bad:**\n\n```js\nclass SomeClass {\n  foo() {}\n}\n\nmodule.exports = new SomeClass();\n```\n\n**Good:**\n\n```js\nconst myModule = {\n  foo() {};\n}\n\nmodule.exports = myModule\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n---\n\n### Prefer exporting factories over Classes\n\nExporting classes forces the caller to use `new X()` This makes it harder to change the internal implementation without breaking the callers.\nUsing factories allows us to change the implementation without changing the callers.\nYou can read more in this [article](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9).\n\n**Bad:**\n\n```js\nclass SomeClass {}\n\nmodule.exports = SomeClass;\n```\n\n**Good:**\n\n```js\nclass SomeClass {}\n\nmodule.exports = (...args) =\u003e {\n  return new SomeClass(...args);\n};\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n---\n\n## Modules and Constructors\n\n**[⬆ back to top](#table-of-contents)**\n\n### A module is never instantiated. \n\nIt is an interface to functions you can use independently or not from the others\n\n**Option 1**:\n\n```js\n/*\n * Good: module.exports is at the top of the file\n * Bad: Using function declaration + relying on hoisting\n */\n\nmodule.exports = {\n\tfoo,\n\tbar\n};\n\nfunction foo() {}\nfunction bar() {}\n```\n\n**Option 2**:\n\n```js\n/*\n * Good: \n *   - Using function expressions\n *   - Easy to call each function from the others\n *   - \n * Bad: \n *   - Hard to differentiate between private and public methods \n *   - Less readable\n *   - Can be bound but won't be clear what this is\n */\n\nconst foo = function foo() {}\nconst bar = function bar() {} \n\nmodule.exports = {\n\tfoo,\n\tbar\n};\n```\n\n**Option 3**:\n\n```js\n/*\n * Good: \n *   - Using function expressions\n *   - Easy to call each function from the others\n *   - Brevity\n *   - Prevent bad this bindings\n * Bad: \n *   - Hard to differentiate between private and public methods \n *   - Can feel a bit too spaghetti with many functions\n *   - Prevent this bindings\n *   - Not usable as object methods (no this possible =\u003e no state)\n */\n\nconst privateMethod = () =\u003e {};\nconst foo = () =\u003e {}\nconst bar = () =\u003e {} \n\nmodule.exports = {\n\tfoo,\n\tbar\n};\n```\n\n**Option 4**:\n\n```js\n/*\n * Good: \n *   - Basically the same as option 4 but can use `interface` to reference other function instead of this\n *   - Object pattern with internal state (can use this)\n *   - Method shortand is nice to read\n *   - Easy to differentiate private / public methods\n * Bad: \n *   - Methods can be bound incorrectly if dereferenced (invalid this / or no this)\n *   - Uses either this or module is not really good\n *   - Allows composition 🔥 with this bindings\n */\n\nconst privateMethod = () =\u003e {};\n\nconst module = {\n  foo() {\n    module.bar() \n  },\n  bar() {}\n}\n\nmodule.exports = module;\n```\n\n**Option 5**:\n\n```js\n/*\n * Good: \n *   - Basically the same as option 4 but can use `interface` to reference other function instead of this\n *   - Object pattern with internal state (can use this)\n *   - Method shortand is nice to read\n *   - Easy to differentiate private / public methods\n * Bad: \n *   - Methods can be bound incorrectly if dereferenced (invalid this / or no this)\n *   - Uses either this or module is not really good\n *   - Allows composition 🔥 with this bindings\n */\n\nconst privateMethod = () =\u003e {};\n\nconst module = {\n  foo() {\n    module.bar() \n  },\n  bar() {}\n}\n\nmodule.exports = module;\n```\n\n**Option 6**:\n\n```js\n/*\n * Good: \n *   - Easy to diff what is internal vs external (private vs public)\n * Bad: \n *   - No central place to know the complete interface of the module (vs a single module.exports)\n *   - Verbose\n */\n\nconst privateMethod = () =\u003e {};\n\nexports.publicMethod = () =\u003e { privateMethod() };\nexports.otherPubMethod = () =\u003e  { exports.publicMethod() };\n\n// or similar\nconst internals = {};\n\ninternals.privateMethod = () =\u003e {};\n\nexports.publicMethod = () =\u003e { internals.privateMethod() };\nexports.otherPubMethod = () =\u003e  { exports.publicMethod() };\n```\n\n- Option 1 \u0026 2 can be ruled out right now.\n- Option 3 \u0026 (4/5) are really good. I like the structure of 4/5 and the brevity of 3.\n- Option 6 is really easy to reason about when coding but more verbose.\n\n**[⬆ back to top](#table-of-contents)**\n\n---\n\n### Constructor\n\nHere you want to pass parameters to the object before instantiation\n\n**Option 1**:\n\n```js\nclass SomeClass {\n  constructor(options) {\n    this.x = options.x;\n  }\n\n  // when available\n  #privateMethod() {}\n\n  publicMethod() {\n    this.#privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n}\n\n\nmodule.exports = SomeClass;\n```\n\n**Option 2**:\n\n```js\nclass SomeClass {\n  constructor(options) {\n    this.x = options.x;\n  }\n\n  // when available\n  #privateMethod() {}\n\n  publicMethod() {\n    this.#privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n}\n\nmodule.exports = (options) =\u003e new SomeClass(options);\n\n//\n\nconst createSomeclass = require('some-class');\n\ncreateSomeclass(options);\n```\n\n**Option 3**:\n\n```js\nclass Controller {\n  constructor(options) {\n    this.x = options.x;\n  }\n \n  // when available\n  #privateMethod() {}\n\n  publicMethod() {\n    this.#privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n\n  // use this to instantiate\n  static create(opts) {\n\t  return new Controller(opts);\n  }\n}\n\nmodule.exports = Controller;\n\n//\nconst Controller = require('controller');\n\nController.create();\n```\n\n**Option 4**:\n\n```js\nfunction SomeClass(options) {\n  this.x = options.x;\n\n\tthis.publicMethodThatNeedsPrivateOptions = () =\u003e {\n    console.log(option.privateKey);\n  }\n}\n\nconst privateMethod = () =\u003e {};\n\nSomeClass.prototype = {\n  publicMethod() {\n    privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n}\n\nmodule.exports = (options) =\u003e new SomeClass(options);\n```\n\n**Option 5**:\n\n```js\nconst privateMethod = () =\u003e {};\n\nconst prototype = {\n  init(options) {\n\t\tthis.x = options.x;\n\n\t\tthis.publicMethodThatNeedsPrivateOptions = () =\u003e {\n      console.log(option.privateKey);\n    }\n  },\n\n\tpublicMethod() {\n    privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n}\n\nmodule.exports = (options) =\u003e {\n  const instance = Object.create(prototype);\n  return instance.init(options)\n}\n```\n\n**Option 6**:\n\n```js\nconst privateMethod = () =\u003e {};\n\nconst prototype = {\n\tpublicMethod() {\n    privateMethod();\n  }\n\n  otherPubMethod() {\n    this.publicMethod();\n  }\n}\n\nmodule.exports = (options) =\u003e {\n  const instance = Object.create(prototype);\n  \n   instance.x = options.x;\n\t instance.publicMethodThatNeedsPrivateOptions = () =\u003e {\n      console.log(option.privateKey);\n   };\n\n   return instance;\n};\n```\n\n**Option 7**:\n\n```js\nconst factory = (options) =\u003e {\n\n  const { x } = options;\n\n\tconst privateMethod = () =\u003e {};\n  const publicMethod = () =\u003e { privateMethod() };\n  const otherPubMethod = () =\u003e { publicMethod() };\n\tconst publicMethodThatNeedsPrivateOptions = () =\u003e {\n    console.log(option.privateKey);\n  };\n\n  return {\n    publicMethod,\n    otherPubMethod,\n    publicMethodThatNeedsPrivateOptions,\n  };\n};\n\nmodule.exports = factory\n```\n\n**[⬆ back to top](#table-of-contents)**\n\n---","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrapi%2Fjavascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrapi%2Fjavascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrapi%2Fjavascript/lists"}