Skip to content

Instantly share code, notes, and snippets.

@rpowis
Last active January 7, 2019 15:05
Show Gist options
  • Save rpowis/71f3782166e7d835b12ffe7740f6b23e to your computer and use it in GitHub Desktop.
Save rpowis/71f3782166e7d835b12ffe7740f6b23e to your computer and use it in GitHub Desktop.
Namespacing conflicting macros

Goals

  1. Nothing higher than the package root should be exposed to views

Stretch goals

  1. Changes to the package structure shouldn't require updates to config
  2. Import paths should map to source paths

1. Prefixed component names

View

{% from "button/macro.njk" import govukButton %}
{% from "hmrc-button/macro.njk" import hmrcButton %}

survey.js

var appViews = [
  path.join(__dirname, '/node_modules/hmrc-frontend/'),
  path.join(__dirname, '/node_modules/hmrc-frontend/components'),
  path.join(__dirname, '/node_modules/govuk-frontend/'),
  path.join(__dirname, '/node_modules/govuk-frontend/components'),
  ...
]

Package

node_modules
├── govuk-frontend
│   └── components
│       └──  button
└── hmrc-frontend
    └── components
        └──  hmrc-button

Goals

Pros

  • Doesn't require a breaking change of govuk-frontend to implement
  • Least verbose and least repetitive. No redundant path segments in imports
  • Maps to package directory structure

Cons

  • Requires convention that departmental versions of patterns be prefixed with <department>-. A department could release a conflicting component without realising which will likely break things for users of that package.
  • Requires that components prefixed with <department>- don't get the department name duplicated in the macro name.
    • Department name could be set in config somewhere to at least abstract it from the core logic.
  • Every directory that's added to the package root needs to be added to config:
    var appViews = [
      path.join(__dirname, '/node_modules/hmrc-frontend/'),
      path.join(__dirname, '/node_modules/hmrc-frontend/layouts'),    
      path.join(__dirname, '/node_modules/hmrc-frontend/components'),
      ...
    ]
    

2. Prepend a directory to components

View

{% from "button/macro.njk" import govukButton %} {# pre 3.0.0 #}
{% from "govuk/button/macro.njk" import govukButton %} {# post 3.0.0 #}
{% from "hmrc/button/macro.njk" import hmrcButton %}

survey.js

var appViews = [
  path.join(__dirname, '/node_modules/hmrc-frontend/'),
  path.join(__dirname, '/node_modules/hmrc-frontend/components'),
  path.join(__dirname, '/node_modules/govuk-frontend/'),
  path.join(__dirname, '/node_modules/govuk-frontend/components'),
  ...
]

Package

node_modules
├── govuk-frontend
│   └── components
│       └── govuk
│           └── button
└── hmrc-frontend
    └── components
        └── hmrc
            └── button

Goals

Pros

  • Smallest/simplest change to import paths
  • A department can't release a conflictingly named component

Cons

  • The import path doesn't match the source path.
  • Every directory that's added to the package root needs to be added to config

3. Prepend a directory at the package root

View

{% from "components/button/macro.njk" import govukButton %} {# pre 3.0.0 #}
{% from "govuk/components/button/macro.njk" import govukButton %} {# post 3.0.0 #}
{% from "hmrc/components/button/macro.njk" import hmrcButton %}

survey.js

var appViews = [
  path.join(__dirname, '/node_modules/hmrc-frontend/'),
  path.join(__dirname, '/node_modules/govuk-frontend/'),
  ...
]

Package

node_modules
├── govuk-frontend
│   └── govuk
│       └── components
│           └──  button
└── hmrc-frontend
    └── hmrc
        └── components
            └──  button

Goals

Pros

  • Only one config entry for everything in the package
  • The import path matches the source path

Cons

  • More verbose and repetitive import paths

4. Namespaced npm packages

View

{% from "button/macro.njk" import govukButton %} {# pre 3.0.0 #}
{% from "govuk-frontend/components/button/macro.njk" import govukButton %} {# post 3.0.0 #}
{% from "hmrc-frontend/components/button/macro.njk" import hmrcButton %}

survey.js

var appViews = [
  path.join(__dirname, '/node_modules/@hmrc/'),
  path.join(__dirname, '/node_modules/@govuk/'),
  ...
]

Package

node_modules
├── @govuk
│   └── govuk-frontend
│       └── components
│           └──  button
└── @hmrc
    └── hmrc-frontend
        └── components
            └──  hmrc-button

Goals

Pros

  • Namespacing the npm package allows for more granular packages in the future
    • i.e. @hmrc/header, which could depend on @govuk/core, and/or extend @govuk/header

Cons

  • Most verbose and repetetive import paths
    • Although this could be reduced a bit by flattening everything to the root of the package (i.e. {% from "govuk-frontend/button/macro.njk" import hmrcButton %})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment