Skip to content

NYULibraries/primo-customization

Repository files navigation

Primo Customization for NYU

Prerequisites

  • Node 16.17.0 or higher (nvm recommended)
  • yarn

Getting started


Install

 git clone [email protected]:NYULibraries/primo-customization.git
 cd primo-customization/
 yarn
 # See section "Where does primo-explore-devenv/ come from?"
 # https://github.com/NYULibraries/primo-customization#where-does-primo-explore-devenv-come-from
 cd primo-explore-devenv/
 yarn

Start local CDN server

To run the CDN server in the foreground with log messages to the screen:

# http://localhost:3000/
yarn cdn-server [OPTIONAL CDN PATH]

If CDN PATH is not specified, static files are served from the default file system test/e2e/fixtures/cdn/.

CDN PATH can be a relative or absolute path. One useful setup can be to serve from a local clone of primo-customization-cdn. For example:

# http://localhost:3000/ serving from a local clone of `primo-customization-cdn`
# located in the same directory as this repo.
yarn cdn-server ../primo-customization-cdn

Another useful setup is to have a top-level cdn/ directory in which is a symlink to the primo-customization/ subdirectory of a local clone of primo-customization-cdn. This mirrors how local development was done before the CDN file system was split out into the separate primo-customization-cdn repo. Git operations must be done in the CDN repo, but all other work can be done in this repo via the symlink. The ./cdn/ rule in .gitignore was added to accommodate this setup.

Example:

primo-customization> ls -1 ../primo-customization-cdn/
README.md
docker-compose.yml
primo-customization
scripts
primo-customization> mkdir cdn
primo-customization> cd cdn/
cdn> ln -s ../../primo-customization-cdn/primo-customization/
cdn> cd ../
primo-customization> yarn cdn-server cdn
yarn run v1.22.19
warning package.json: No license field
$ node tools/cdn-server/server.mjs cdn
CDN server started on http://localhost:3000

...

Using Docker Compose (automatically started by primo-explore-devenv service):

# http://localhost:3000/ serving from a copy of `test/e2e/fixtures/cdn/` in the container.
docker compose up cdn-server

To have the Docker Compose cdn-server service use a file system other than the default test/e2e/fixtures/cdn/, uncomment the volumes key and mount the local file system in the container at /app/cdn.


Start local Primo (primo-explore-devenv/)

Local Primo: http://localhost:8003/discovery/search?vid=[VIEW]

# http://localhost:8003/discovery/search?vid=01NYU_INST:NYU_DEV
yarn primo-explore-devenv:run:nyu:dev
# http://localhost:8003/discovery/search?vid=01NYU_INST:NYU
yarn primo-explore-devenv:run:nyu:prod
# http://localhost:8003/discovery/search?vid=01NYU_INST:TESTWS01
yarn primo-explore-devenv:run:nyu:testws01
# http://localhost:8003/discovery/search?vid=[VID]
yarn primo-explore-devenv:run [VIEW]

Using Docker Compose (starts cdn-server service automatically):

VIEW=[VIEW] docker compose up primo-explore-devenv

For example:

# http://localhost:8003/discovery/search?vid=01NYU_INST-NYU_DEV
VIEW=01NYU_INST-NYU_DEV docker compose up primo-explore-devenv

Tests


Where does primo-explore-devenv/ come from?

primo-explore-devenv/ is a customized snapshot of ExLibris's primo-explore-devenv ("The Primo New UI Customization Workflow Development Environment").

This subdirectory was created using script scripts/set-up-primo-explore-devenv.sh:

nvm use 16.17.0
./scripts/set-up-primo-explore-devenv.sh

This is an updated version of the convenience script that was written during our prototyping phase for setting up primo-explore-devenv/ as an external dependency, before we decided to simply have it be a part of this repo. It can serve as a reference when/if we need to update primo-explore-devenv/. Depending on what changed in the upstream, it could with some minor updates be used to refresh the directory.


Primo VE view and vid naming conventions

Fully qualified view names

Fully qualified view names consist of the institution code and a view name joined by a hyphen, with all letters in uppercase. The institution codes are created by Ex Libris, and each code designates an Institution Zone (IZ). The view names within each IZ are created by NYU. Currently, we are following this convention:

  • Prod view name: abbreviation for the campus -- ex. NYU
  • Dev view name: the prod view name with an added "_DEV" suffix -- ex. NYU_DEV

The fully qualified view names for NYU New York campus:

  • Prod: 01NYU_INST-NYU
  • Dev: 01NYU_INST-NYU_DEV

NOTE: We have one view name "TESTWS01" which does not follow any particular current naming convention. It was originally a view created in the sandbox domain for initial testing, prototyping, and experimentation. We created the same view in real domain to provide developers with a playground view which is not being used by non-developer parties.

View names are used for directory names in our various repositories, and are also used for customization package zipfile basenames. For example, for the NYU New York campus prod view:

  • This repo
    • Source: custom/01NYU_INST-NYU/
    • Customization package zipfile: primo-explore-devenv/packages/01NYU_INST-NYU.zip
  • primo-customization-cdn
    • Source: primo-customization/01NYU_INST-NYU/

vid values/names

Values for the vid query param in Primo VE discovery URLs are view names with the hyphens replaced by ':' characters. For example, for the NYU New York campus prod view, the vid is "01NYU_INST:NYU".


Primo customization package

Create new Primo customization package

This command will create a new package in primo-explore-devenv/packages/:

# Creates ./primo-explore-devenv/packages/01NYU_INST-NYU_DEV.zip
yarn primo-explore-devenv:create-package:nyu:dev
# Creates ./primo-explore-devenv/packages/01NYU_INST-NYU.zip
yarn primo-explore-devenv:create-package:nyu:prod
# Creates ./primo-explore-devenv/packages/01NYU_INST-TESTWS01.zip
yarn primo-explore-devenv:create-package:nyu:testws01
# Creates ./primo-explore-devenv/packages/[VIEW].zip
yarn primo-explore-devenv:create-package [VIEW]

Using Docker Compose:

VIEW=[VIEW] docker compose up create-package

Deploy new Primo customization package


Primo customization: "css Recipe 1 - Color Scheme (Starting from August 2016 Release)"

See primo-explore-package/VIEW_CODE/css/README.md

This command will create from custom/[VIEW]/colors.json:

  • custom/[VIEW]/css/app-colors.css
  • custom/[VIEW]/scss/

Note that currently we use CDN CSS files to customize colors. The generated app-colors.css files should be moved from the customization package to the appropriate paths in the CDN. The scss/ directories can simply be deleted.

yarn primo-explore-devenv:app-css:nyu:dev
yarn primo-explore-devenv:app-css:nyu:prod
yarn primo-explore-devenv:app-css:nyu:testws01

Using Docker Compose:

VIEW=[VIEW] docker compose up app-css

Deploy new Primo customization package


Customized version of ExLibris "showDirectives" bookmarklet

To generate our custom version of the ExLibris "showDirectives" bookmarklet primo-explore-package/VIEW_CODE /showDirectives.txt: in tmp/show-directives.txt:

yarn bookmarklet

Using Docker Compose:

docker compose up bookmarklet

Update 05-autogenerated-custom-directives.js and exlibris-template-cache-code.txt files

To update custom/00_common/js/05-autogenerated-custom-directives.js, which contains the definitions for the hundreds of generic component that are customized by the template HTML files in the CDN:

# Update from real domain
yarn update-autogenerated-directives:real
# Update from sandbox
yarn update-autogenerated-directives:sandbox

Using Docker Compose:

# Update from real domain
docker compose up update-autogenerated-directives-from-real
# Update from sandbox
docker compose up update-autogenerated-directives-from-sandbox

These commands will first update scripts/exlibris-template-cache-code.txt and then regenerate custom/00_common/js/05-autogenerated-custom-directives.js from the updated template cache code file. Note that it is possible for the template cache code file to change in ways that do not result in changes to the 05-autogenerated-custom-directives.js file.

To update custom/00_common/js/05-autogenerated-custom-directives.js from the existing scripts/exlibris-template-cache-code.txt, without first updating that template cache code file from a live Primo VE instance:

yarn generate-autogenerated-directives

Using Docker Compose:

docker compose up generate-autogenerated-directives

Note that as a side effect of running any of the commands above, blank HTML template files will be created for new components in all html/ subdirectories of all view directories in cdn/primo-customization/ if that path exists. This top-level path might exist as a symlink to a local primo-customization-cdn clone -- see the suggestion in Start local CDN server. After the new HTML files are created, they can be checked into that separate repo, after making sure that repo has been set to a state where it is ready for the changes to be committed (i.e. all remote update have been fetched, the appropriate branch is checked out, etc.)

ESLint

Fix ESLint errors

To fix all ESLint errors in files for which we enforce ESLint rules:

yarn eslint:fix

Using Docker Compose:

docker compose up eslint-fix

New configuration system

ESLint is transitioning to a new configuration system: Configuration Files

Warning We are transitioning to a new config system in ESLint v9.0.0. The config system shared on this page is currently the default but will be deprecated in v9.0.0. You can opt-in to the new config system by following the instructions in the documentation.

We are opting-in to the new system by putting our configuration in eslint.config.js. JetBrains does not appear to support the new system yet, and VS Code might not either (not confirmed). To enable seamless linting in IDEs, we also have a script that generates and old style .eslintrc.cjs file from the new style eslint.config.js config file, which will be automatically detected by the JetBrain IDEs.

To regenerate .eslintc.cjs:

yarn eslint:cjs-file
# The script currently does not generate an ESLint-compliant file, so we need to fix it.
yarn eslint:fix

Using Docker Compose:

docker compose up eslint-cjs-file
# The script currently does not generate an ESLint-compliant file, so we need to fix it.
yarn eslint-fix

Note that it is not really possible to have .eslintrc.cjs import the rules directly from eslint.config.js because the former uses the CommonJS style module system and the latter uses ESM. Moreover, the eslint.config.js spec specifies returning an array and not an object, making import by CommonJS module .eslintrc.cjs not feasible.


CDNs

To update CDN content, run scripts/update-cdn.sh:

# Update cdn-dev
scripts/update-cdn.sh cdn-dev

# Update sandbox S3/CloudFront pair associated with your NetID
scripts/update-cdn.sh sandbox [your NetID]

Dev

Sandbox

Local

See Start local CDN server.


Archived code

Have CloudFront serve a custom empty 403 error page when a non-existent templateUrl file is requested

Ideally, we would not want to be generating empty templateUrl files in S3 for all custom directives that haven't been customized. We set up our S3 bucket and CloudFront instance in AWS nyulibraries-webservices to serve and empty HTML page whenever S3 returned a 403 error to CloudFront for a request for a non-existing file, then deleted all HTML files that had no customization content. It works well, but we can't necessarily make the same changes in nyulibraries and nyulits dev and prod S3/CloudFront setups right away. We would first have to create separate S3 buckets and CloudFront distributions because the CloudFront custom error page feature is global, and CDN and dev CDN are shared with other websites and applications. archived_use-custom-403-response-html-file-for-empty-custom-directives

Only generate components for HTML files listed in a manifest

We originally thought we could limit the generation of customizable AngularJS components to only those which had corresponding template files in cdn/primo-customization/01NYU_INST-TESTWS01/html/, but unfortunately this proved to not be viable due to a race condition which sometimes led to the fetching of the manifest to occur after the AngularJS application had already been bootstrapped. There seemed to be no way to guarantee a proper execution sequence. Both fetching a static file from the CDN and making a request to a Lambda@Edge function that provided a realtime manifest were prone to the timing bug. It's possible that any async calls made in the customization package create race conditions, even when using async/await.

Previous experiments in CDN-based customization

The current approach being used for CDN-based customization was one of six that we experimented with in anticipation of migration to Primo VE. All the POCs in their final form can be retrieved through git tag archived_customization-approaches-proofs-of-concept.


References