From 32bcfa1f3fc5fb2164fab772b80aa8beac29edae Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 12:26:59 -0500 Subject: [PATCH 1/6] feat: addition of web development skeleton (back-end and front-end) --- docs/software_development/.pages | 2 +- docs/software_development/Web_Development/back-end/index.md | 2 ++ docs/software_development/Web_Development/front-end/index.md | 2 ++ docs/software_development/Web_Development/index.md | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 docs/software_development/Web_Development/back-end/index.md create mode 100644 docs/software_development/Web_Development/front-end/index.md create mode 100644 docs/software_development/Web_Development/index.md diff --git a/docs/software_development/.pages b/docs/software_development/.pages index 813ffffb6..96abe078e 100644 --- a/docs/software_development/.pages +++ b/docs/software_development/.pages @@ -6,4 +6,4 @@ nav: - Languages - Version_Control - Remote_Development - - ... + - Web_Development diff --git a/docs/software_development/Web_Development/back-end/index.md b/docs/software_development/Web_Development/back-end/index.md new file mode 100644 index 000000000..3e6df5b78 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/index.md @@ -0,0 +1,2 @@ +# Back-end +This section covers some core concepts, libararies, frameworks, and tools related to back-end web application development pertaining to the lab. \ No newline at end of file diff --git a/docs/software_development/Web_Development/front-end/index.md b/docs/software_development/Web_Development/front-end/index.md new file mode 100644 index 000000000..5f4d9a3f3 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/index.md @@ -0,0 +1,2 @@ +# Front-end +This section covers some core concepts, libararies, and frameworks related to front-end web application development pertaining to the lab. \ No newline at end of file diff --git a/docs/software_development/Web_Development/index.md b/docs/software_development/Web_Development/index.md new file mode 100644 index 000000000..5ce60102b --- /dev/null +++ b/docs/software_development/Web_Development/index.md @@ -0,0 +1,3 @@ +# Web Development + +This section of the handbook will focus on the core web development concepts, libraries, frameworks, and tools used in the lab. It is broken up into two main sections **back-end** and **front-end**. Back-end will discuss primarily API development, heavily focusing on frameworks, libraries, and tools used across the lab. Front-end cover UI development in the lab, also primarily focusing on frameworks, libraries, and tools needed and used. \ No newline at end of file From 568bf760c48de450cb5b980fd2726f544b2614f7 Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 12:29:21 -0500 Subject: [PATCH 2/6] feat: addition of DOM page and libraries and frameworks index page --- .../Web_Development/front-end/dom.md | 60 +++++++++++++++++++ .../styling_libraries_and_frameworks/index.md | 3 + 2 files changed, 63 insertions(+) create mode 100644 docs/software_development/Web_Development/front-end/dom.md create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/index.md diff --git a/docs/software_development/Web_Development/front-end/dom.md b/docs/software_development/Web_Development/front-end/dom.md new file mode 100644 index 000000000..bec7ebb69 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/dom.md @@ -0,0 +1,60 @@ +# DOM + +!!! note + This isn't necessary information for software development in lab but it provides better rounded knowledge of web development. + +The DOM is the data representation of the objects that comprise the structure and contents of a document on the web. + +### What is a web document? + +A web document is simply a file you access through a web browser. This is typically written at it's core in HTML (HyperText Markup Language). It defines the structure and content of a web page. + +### What is the DOM + +In short, the DOM is a programming interface for all web documents. It represents the page so that programs can change the document structure, style, and content. The DOM is built using multiple APIs that work together. + +In most cases the DOM serves as a programmatic representation of an HTML document. It's how browsers internally structure your page in memory so that code such as JavaScript can interact with it. JavaScript will interact with the DOM to change things in memory to adjust the web document. + +### Why can't JavaScript directly interact with HTML instead of the DOM? + +JavaScript can't directly interact with raw HTML text because once a browser has loaded a page, that HTML text is no longer "alive". Once a browser page has loaded it has been parsed into a structured model (the DOM) that JavaScript can work with in memory to change the rendered page. + +To clarify this further, HTML lives on the server hosting a web page, whereas JavaScript lives in the browser, therefore allowing for constant manipulation of the web page by working with DOM in memory. + +If you make changes to an HTML document, you must reload the page to view the changes. If you manipulate the DOM, you can see those changes real-time, due to it living in memory. + +### Do browsers create their own DOM? + +Yes, all browsers build their own DOM from HTML. However, each browser uses the same specifications given by [W3C](https://www.w3.org/TR/WD-DOM/introduction.html) / [WHATWG](https://dom.spec.whatwg.org/) to ensure the JavaScript used to manipulate the DOM will act consistently across all. + +### HTML --> DOM --> JavaScript interactions simplified + +#### HTML + +Defines the structure and content of a web page. It is made up of just plane text. **Often thought of as the recipe or blueprint.** + +###### *Example* +```HTML +

Hello

+

This is a paragraph

+``` + +#### DOM + +Turns the plain text into a tree of objects in memory. **Often thought of as the ingredients or materials** + +###### *Example* + + Document + └── html + └── body + ├── h1 + └── p + +#### JavaScript + +Manipulates the in memory tree of objects. **Often thought of as the chef/laborer who works with the ingredients/materials** + +###### *Example* + + `document.querySelector("h1").textContent = "Goodbye";` \ No newline at end of file diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/index.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/index.md new file mode 100644 index 000000000..4aa16f123 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/index.md @@ -0,0 +1,3 @@ +# Styling Libraries and Frameworks + +A variety of styling libraries/frameworks have been used in the lab throughout the years. These include a mix of both [component libraries](https://prismic.io/blog/react-component-libraries#what-are-react-ui-component-libraries) and [utility-first frameworks](https://heydonworks.com/article/what-is-utility-first-css/) \ No newline at end of file From 31dbdaf4a13fc58fe8b9aa3a5f9655449c31efe5 Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 13:05:30 -0500 Subject: [PATCH 3/6] feat: addition of styling libraries section along with pages for tailwind, primereact, and styled-components --- .../libraries_and_frameworks/index.md | 2 + .../primereact.md | 7 ++ .../styled.md | 27 +++++ .../tailwindcss.md | 99 ++++++++++++++++++ .../images/postman-collections.png | Bin 0 -> 35445 bytes .../images/tailwind-component.png | Bin 0 -> 10867 bytes 6 files changed, 135 insertions(+) create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/index.md create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/primereact.md create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/styled.md create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/tailwindcss.md create mode 100644 docs/software_development/Web_Development/images/postman-collections.png create mode 100644 docs/software_development/Web_Development/images/tailwind-component.png diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/index.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/index.md new file mode 100644 index 000000000..129a90e80 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/index.md @@ -0,0 +1,2 @@ +# Libraries and Frameworks +This section focuses on libraries and frameworks used in the front-end development within the lab. It will mainly cover React and styling libraries used. \ No newline at end of file diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/primereact.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/primereact.md new file mode 100644 index 000000000..9332b86d1 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/primereact.md @@ -0,0 +1,7 @@ +# PrimeReact + +[PrimeReact](https://primereact.org/) is a component library. Unlike TailwindCSS that deals with only styling components, PrimeReact provides premade components right out of the box. It is used in several projects and versions vary quite significantly. All of the new lab projects use version 10.9.7. + +PrimeReact really comes in handy for components that would take many hours to manually build to perfect functionality. This includes the [virtual scrollers](https://primereact.org/virtualscroller/), [accordions (dropdowns)](https://primereact.org/accordion/), [Toasts (popups)](https://primereact.org/toast/), [Dialog popups (modals)](https://primereact.org/dialog/), [tooltips](https://primereact.org/tooltip/), [calendars](https://primereact.org/calendar/), and [text editors](https://primereact.org/editor/). + +It is very good to use PrimeReact components where the engineering feat would be high but something out of the box would provide a good base component to work with. However, I would be weary on getting carried away with using PrimeReact premade components for everything. PrimeReact components can sometimes be very tricky to edit to your styling needs, so creating raw components using [TailwindCSS](./tailwindcss.md) is usually better if the component is not too much of a feat (since you will have much more styling control with TailwindCSS). \ No newline at end of file diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/styled.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/styled.md new file mode 100644 index 000000000..5e91dfd6d --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/styled.md @@ -0,0 +1,27 @@ +# Styled-components + +[Styled-components](https://styled-components.com/) is another JavaScript library utilized for styling web applications components. It's frequently used in many of the legacy applications such as PharmacoDB, SynergxDB, ToxicoDB, KulGaP, XevaDB, PredictIO, cclid, ORCESTRA, and the lab website. So, for maintaing sake, it is good to have a good grasp on how styled-components works and how it differs from defining raw CSS or utilizing traditional utility-first styling (like [TailwindCSS](./tailwindcss.md)). + +When using styled-components, you don't directly create a classes, instead you create a new instance of a component, with the option of adding embedded classes afterwards. + +In the example below as you can see we define a new div component called "Wrapper" with it's own unique stylings. Within the "Wrapper" div component we also define a local classname called "title" which only exists in the scope of the component it is defined within. This does help significantly to keep styling local and not have too many spill over issues that occur when editing styling classes and having many cascading effects in the rest of your application where they are used. + +```JavaScript +const Wrapper = styled.div` + padding: 4em; + background-color: white; + .title { + font-size: 1.5em; + text-align: center; + color: #BF4F74; + } +`; + +return ( + +

+ Hello World! +

+
+); +``` \ No newline at end of file diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/tailwindcss.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/tailwindcss.md new file mode 100644 index 000000000..5fe1615db --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/styling_libraries_and_frameworks/tailwindcss.md @@ -0,0 +1,99 @@ +# TailwindCSS + +[TailwindCSS](https://v3.tailwindcss.com/docs/installation) is a utility-first framework for styling components in React. In every new web application project within the lab Tailwind is installated and utilized for core styling. + +Due to our developer team being quite small in the lab, utilizing Tailwind is crucial when developing web applications in a timely manner because it removes several steps when styling components, hence saving a signficant amount of time. Traditionally, when styling a React component you must assign it a class, create a CSS file, create a new class in the CSS file that corresponds to the class given to your component, then write in your stylings. When Tailwind is installed and configured it has a large collection of preset classes (utility classes) that can be written inline on a component classname that will apply certain stylings to it. This means that you **NEVER** need to create extra CSS files and rarely define your own classes. + +Above the time saving aspect, Tailwind also ensures consistent styling (due to predefined utilities), easy to setup inline response designs utilizing media queries (this is not possible inline without Tailwind), and hover/focus, along with other state variants. + +In lab projects we primarily use v3.4.17 but v4 has been recently released, so newer applications can bump to take advantage of their new simplified setup, "high performance engine", larger colour palette, and new 3D transformations. + +## Tailwind Example + +If you want to add a `flex` display orientation to a div element, you would simply write it inline like such: + +```JavaScript +
+ . + . + . +
+``` + +This would apply the following classes manually without creating a css file for it + +```CSS +.flex { + display: flex; +} +.flex-row { + flex-direction: row; +} +``` + +## Robust Tailwind Comparison + +![tailwind-component](../../../images/tailwind-component.png) + +If you want to create the above component with raw CSS, you would need to define the following. + +```JavaScript +
+
+ +
+
+

ChitChat

+

You have a new message!

+
+
+ + +``` + +If you utilize Tailwind you can simply write the following: + +```JavaScript +
+
+ ChitChat Logo +
+
+
ChitChat
+

You have a new message!

+
+
+``` + +As you can see, once you are comfortable utilizing Tailwind styling, it will become significantly faster to develop core components of an application. \ No newline at end of file diff --git a/docs/software_development/Web_Development/images/postman-collections.png b/docs/software_development/Web_Development/images/postman-collections.png new file mode 100644 index 0000000000000000000000000000000000000000..c6d76b8519dcfcfee499756c6da55badef056938 GIT binary patch literal 35445 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 literal 0 HcmV?d00001 From 91a2b5c10a983f46f1807376f83c9254f5a191e6 Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 13:07:02 -0500 Subject: [PATCH 4/6] feat: addition of react section in front-end along with a react overview page and react hooks page --- .../libraries_and_frameworks/React/react.md | 45 ++++++++++++++++ .../React/react_hooks.md | 52 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react.md create mode 100644 docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react_hooks.md diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react.md new file mode 100644 index 000000000..ade41ed69 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react.md @@ -0,0 +1,45 @@ +# React + +React is a JavaScript library for building UIs. It follows a component-based architecture that allows for easy manipulation of the web browsers [virtual DOM](../../dom.md) for dynamic and interactive applications. + +React is the most crucial library used in the lab for front-end development. This library remains consistent across all web applications and will continue to be the case, versions do vary though. + +For the most part React applications are built as single-page applications, meaning a singular HTML page exists as a base that has it's contents translated to the DOM, which can be constantly manipulated using a mixture of JavaScript/React. + +For syntax sake, i like to think of React as a combination between JavaScript and HTML into a singular application workflow. React removes many complexities needed for JavaScript manipulation of the DOM and uses HTML(ish) syntax. + +### Ex: Pressing a button in JavaScript +In JavaScript you must add a listener to fetch the element in DOM. Then manipulate the DOM yourself. +```JS + + +``` + +### Ex: Pressing a button in React +In React you don't need to add listeners or even intentionally interact with the DOM. By simply talking React language, it'll work with the DOM for you. + +```JSX +function CounterButton() { + const [count, setCount] = useState(0); + return ( + + ); +} +``` + +**Note:** In the example above useState stores the current value of ***count*** and a function (***setCount***) to update it. Whenever the update function (***setCount***) is called, an automatic re-render is triggered so the UI can reflect the change. This completely removes the heavy lifting of needing to get the element by Id, add a click event listener, then manually update the text content when the count value changes. + +### Key Characteristics +- Reusability: Components/elements are designed to be used multiple times across multiple parts of an application. +- Modularity: Each component encapsulates it's own logic and styling. Making the code easier to manage, test, and debug. +- Encapsulation: Components tend to manage their own state and behavior, which avoids unintended behaviors in other parts of the app. + diff --git a/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react_hooks.md b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react_hooks.md new file mode 100644 index 000000000..141426247 --- /dev/null +++ b/docs/software_development/Web_Development/front-end/libraries_and_frameworks/React/react_hooks.md @@ -0,0 +1,52 @@ +# React Hooks +React hooks are special functions that let you "hook into" React features. This includes things like state, lifecycle, and context, without writing classes. They were introduced in React 16.8 (2019) + +Before hooks came along, React components were either +- Class components (with this.state, componentDidMount, etc) +- Stateless functional components (no lifecycle or state) + +Hooks let you write everything as a simple function component, while still giving you: +- State (useState) +- Lifecycle effects (useEffect) +- Context (useContext) +- References (useRef) + +### useState +Stores local, reactive state in a function component. Calling the setter triggers a re-render. +Ex. + +```JSX +function CounterButton() { + const [count, setCount] = useState(0); + return ( + + ); +} +``` + +Same code functionality pre Hooks: +```JS +class CounterButton extends React.Component { + constructor(props) { + super(props); + this.state = { count: 0 }; + this.increment = this.increment.bind(this); + } + + increment() { + this.setState(prev => ({ count: prev.count + 1 })); + } + + render() { + return ( + + ); + } +} +``` + +TO BE CONTINUED... \ No newline at end of file From a57ef271cb9d7a951dfaac5d308b783abb95af94 Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 14:03:09 -0500 Subject: [PATCH 5/6] feat: addition of tools section and postman page in backend development --- .../Web_Development/back-end/index.md | 2 +- .../Web_Development/back-end/tools/postman.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 docs/software_development/Web_Development/back-end/tools/postman.md diff --git a/docs/software_development/Web_Development/back-end/index.md b/docs/software_development/Web_Development/back-end/index.md index 3e6df5b78..40ebf7329 100644 --- a/docs/software_development/Web_Development/back-end/index.md +++ b/docs/software_development/Web_Development/back-end/index.md @@ -1,2 +1,2 @@ # Back-end -This section covers some core concepts, libararies, frameworks, and tools related to back-end web application development pertaining to the lab. \ No newline at end of file +This section covers some core concepts, libararies, frameworks, and tools related to back-end web application development related to the lab. \ No newline at end of file diff --git a/docs/software_development/Web_Development/back-end/tools/postman.md b/docs/software_development/Web_Development/back-end/tools/postman.md new file mode 100644 index 000000000..9b043ab8d --- /dev/null +++ b/docs/software_development/Web_Development/back-end/tools/postman.md @@ -0,0 +1,13 @@ +# Postman + +Postman is a free downloadable tool primarily used for testing API's or web sockets. Within Postman you can save collections of API routes and/or socket connections dedicated to a project and specific project functionality. + +![postman-collections-image](../../images/postman-collections.png){: style="height:100%;width:100%"} + +Where Postman is most useful: + +1. Constructing an API from the ground up. This is because you can quickly swap arugments, adjust headers, and retrigger the route frequently. +2. Testing queries of an external API. This is because errors are formatted which makes it easier to digest (errors are common when querying a new API), +3. Having the ability to share your created collections with new project members, new developers, or even external collaborators. +4. Being able to easily pick up where you left off years/months after working with an API. + From b2595b872b0a9ddf80a486669acfc4b9ec175106 Mon Sep 17 00:00:00 2001 From: mattbocc Date: Tue, 6 Jan 2026 15:23:14 -0500 Subject: [PATCH 6/6] feat: addition of node and npm pages. Also added skeleton TODO for ExpressJS and NestJS --- .../libraries_and_frameworks/expressjs.md | 1 + .../libraries_and_frameworks/index.md | 3 + .../libraries_and_frameworks/nestjs.md | 1 + .../Web_Development/back-end/node/node.md | 46 +++++++++++ .../Web_Development/back-end/node/npm.md | 81 +++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 docs/software_development/Web_Development/back-end/libraries_and_frameworks/expressjs.md create mode 100644 docs/software_development/Web_Development/back-end/libraries_and_frameworks/index.md create mode 100644 docs/software_development/Web_Development/back-end/libraries_and_frameworks/nestjs.md create mode 100644 docs/software_development/Web_Development/back-end/node/node.md create mode 100644 docs/software_development/Web_Development/back-end/node/npm.md diff --git a/docs/software_development/Web_Development/back-end/libraries_and_frameworks/expressjs.md b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/expressjs.md new file mode 100644 index 000000000..731ea87f5 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/expressjs.md @@ -0,0 +1 @@ +# ExpressJS \ No newline at end of file diff --git a/docs/software_development/Web_Development/back-end/libraries_and_frameworks/index.md b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/index.md new file mode 100644 index 000000000..e9c16c371 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/index.md @@ -0,0 +1,3 @@ +# Back-end Libraries and Frameworks + +This section of the handbook mainly focuses on the backend libraries and frameworks pertaining to API development. \ No newline at end of file diff --git a/docs/software_development/Web_Development/back-end/libraries_and_frameworks/nestjs.md b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/nestjs.md new file mode 100644 index 000000000..2cf5be0f1 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/libraries_and_frameworks/nestjs.md @@ -0,0 +1 @@ +# NestJS \ No newline at end of file diff --git a/docs/software_development/Web_Development/back-end/node/node.md b/docs/software_development/Web_Development/back-end/node/node.md new file mode 100644 index 000000000..50e596ed5 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/node/node.md @@ -0,0 +1,46 @@ +# NodeJS + +[NodeJS](https://nodejs.org) is a runtime environment that allows you to run JavaScript code outside of a browser. By default all browsers have compilers that can interpret and execute JavaScript code, hence they can render web applications that are using React, Vue, Angular, or plain JS seamlessly. However, when running JavaScript code outside of a browser compiler, you will need to have NodeJS installed. + +Many different projects in the lab use different versions of Node so using a tool such as a NVM (Node Version Manager) is a must. A NVM allows you to install and toggle between different versions of Node which is important since different projects utilize different library/package versions only compatible with specific node versions. + +Most legacy projects in the lab use Node version 14-16. This includes projects like PharmacoDB, SynergxDB, ToxicoDB, KulGaP, XevaDB, PredictIO, cclid, and ORCESTRA. More recent projects like the Pmatch web-app, Science Portal, CoBE, lab website, and the new ORCESTRA rework fall into Node versions 18-22. If new applications are to be created in the lab it is recommended to adopt newer node versions (as of writing this that's 22) so we can ensure the Node versions and packages installed for them will be updated and maintained for many years to come and will not require manual package updates as frequently. + +## Installation (Mac/Linux and Windows) + +For Mac/Linux users you can install an NVM [here](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script) + +For window users you will need to install a differerent NVM [here](https://github.com/coreybutler/nvm-windows) + +Both NVMs work very similarly and provide almost identical functionality for installing and toggling between Node versions. + +### Listing current versions: +``` Bash +nvm list + v16.20.1 + v16.20.2 + v18.16.0 +-> v18.19.1 + v20.17.0 + v22.21.1 + v24.12.0 +``` + +### Installing New Versions + +``` Bash +nvm install 21 +Downloading and installing node v21.7.3... +Downloading https://nodejs.org/dist/v21.7.3/node-v21.7.3-darwin-arm64.tar.xz... +########################################################### 100.0% +Computing checksum with shasum -a 256 +Checksums matched! +Now using node v21.7.3 (npm v10.5.0) +``` + +### Toggling New Versions + +``` Bash +nvm use 21.7.3 +Now using node v21.7.3 (npm v10.5.0) +``` \ No newline at end of file diff --git a/docs/software_development/Web_Development/back-end/node/npm.md b/docs/software_development/Web_Development/back-end/node/npm.md new file mode 100644 index 000000000..be1d8e534 --- /dev/null +++ b/docs/software_development/Web_Development/back-end/node/npm.md @@ -0,0 +1,81 @@ +# npm (Node Package Manager) + +npm is the default package manager bundled with Node when installing directly from [NodeJS](https://nodejs.org/) or via a [Node Version Manager (NVM)](./node.md#installation-maclinux-and-windows). npm consists of a CLI tool (primarily used for installing packages and executing code/tests) and it also has access to the largest online software registry (containing millions of different packages). + +Similarlily to Pixi, npm focuses on localized package management rather than global. Each project contains it's own package.json file which includes the following belonging to the respective project: + +- A list of packages and their versions +- Scripts +- Licenses +- Authors +- Project description +- ... + +The localized packages ensure the runtime Node environment has access **ONLY** to the packages needed for the current execution. This avoids environment managemenet and cross project dependency issues commonly faced using pip or conda for Python projects. + +By default the npm CLI has a baked in "install" command that will install all packages within the current working directory. For the project you are currently inside of, simply run `npm install`. This will search for a package.json file in the local directory and install the package versions listed there inside of a folder called `node_modules`. + +# Scripts +For any project there are usually several scripts (often referred to as tasks in other package managers) preconfigured for repeated processes. This usually includes building (build), start/dev (live executing the application), or test (live testing the application). These scripts live within your package.json and will look like each of the code blocks below. + +### Back-end + +#### Standard execution for ExpressJS +Any of these commands can be invoked by writing `npm`, then following with the script/task name Ex. `npm start`. + + +```JSON +"scripts": { + "start": "node app.js", + "devstart": "nodemon app.js", + "test": "mocha --exit" +}, +``` + +#### Standard execution for NestJS +Any of these commands can be invoked by writing `npm` or `npm run`, then following with the script/task name Ex. `npm run start`. + + +```JSON +"scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" +} +``` + + +### Front-end +#### Standard execution for [CRA (Create React App)](https://create-react-app.dev/) + +Any of these commands can be invoked by writing `npm`, then following with the script/task name Ex. `npm start`. + +```JSON +"scripts": { + "start": "react-scripts start", # Runs the project locally (typically executed for development) + "build": "react-scripts build", # Builds the project into a lightweight deployable format + "test": "react-scripts test", # Tests the app using integrated Jest test runner (not configured for most projects in the lab) +}, +``` + +#### Standard execution for [Vite](https://vite.dev/) + +Any of these commands can be invoked by writing `npm run`, then following with the script/task name Ex. `npm run dev`. + +```JSON +"scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" +} +```