Build Tools - egnomerator/misc GitHub Wiki
This documentation on build tools is intended to cover some of the tools available that contribute to the build process which takes your application source code JavaScript files (.js, .jsx, .ts, .tsx) and potentially other assets (e.g. style sheets, images, etc.) as input and produces a bundled file(s) as output for distribution.
For each one of these listed tools, there are alternative tools that accomplish the same thing--I'm just covering the tools I've chosen to use.
Types of tools this documentation covers
- JavaScript Environments (example: Node.js)
- an execution environment for JavaScript
- run package managers, scripts, web servers, etc.
- NVM (Node Version Manager)
- this is a very useful tool for managing multiple versions of Node.js on a single machine
- Package Managers (example: NPM)
- manage JavaScript packages (download/install/uninstall/manage versions)
- JavaScript module bundlers (example: webpack)
- take a set of JavaScript module files as input
- create a dependency tree of the modules
- convert (or bundle) the modules into an output file(s)
- can include minification steps
- some module bundlers (like webpack) can integrate with other tools
- Transpilers (example: Babel, tsc)
- convert input JavaScript files (.js, .jsx, .ts, .tsx)
- produce output file(s) of a target JavaScript version
- could be transpiling JSX and/or TypeScript
- could be transpiling a new version of JavaScript to an older version with wider browser support
Node.js is a server-side JavaScript environment (also see NVM section for helpful Nod.js management tool)
- download/install/manage NPM packages with Node Package Manager (NPM)
- built-in support for CommonJS--Node.js's module format
- execute JavaScript build tasks/scripts
- run JavaScript test runners
- run server-side JavaScript applications
NPM is Node.js's built-in package manager tool.
a few key commands:
-
npm audit
- cross-check NPM packages against a list of known security vulnerabilities
-
npm install
- edit the dependencies of an application by installing an NPM package
-
npm ci
- remove any currently installed NPM packages
- download a full dependency tree of NPM packages to match what is specified in the
package-lock.json
file - this command is mainly intended for continuous integration
- it also can help ensure all developers are developing and building against the exact same tree of dependencies
NPM config files for an Application
package.json
-
"scripts"
key- configures how node behaves when you need to run a build
-
"browserslist"
key- configures the web browsers and versions the app will support
-
"dependencies"
- always use flag
--save-exact
(my personal recommendation--lock versions down) - configures dependencies--including versions used
- these dependencies are a part of the production build output which the user's browser will download
- be highly selective about what dependencies are listed here
- always use flag
-
"devDependencies"
key- use NPM install command's
--save-dev
flag to ensure a package is installed as a devDependency- e.g.
npm install --save-dev --save-exact [email protected]
- e.g.
- always use flag
--save-exact
(my personal recommendation--lock versions down) - configures devDependencies--including versions used
- these dependencies are NOT a part of the production build output
- select these dependencies based on development needs such as:
- build tools (e.g. Webpack, Babel, etc.)
- testing frameworks (e.g. Jest)
- use NPM install command's
package-lock.json
- DO track this file with source control
- this file helps ensure all developers are working with the exact same dependency tree of node modules
- maintains a record of the full node package dependency tree--including versions used
- very commonly, node modules depend on other node modules, so be careful selecting dependencies and be aware of the sub-dependencies
-
IMPORTANT:
- NPM command:
npm install
- e.g.
npm install --save-dev --save-exact [email protected]
- e.g.
- this command will add a new dependency to the application
- (the
--save-dev
and--save-exact
flags are not required)
- (the
-
--save-dev
flag: the package will NOT be included in the build output (it won't be deployed)- common practice is to use this flag unless you need the package included in the build output
- example: React -- DON'T use
--save-dev
because this package needs to be in the build output so a React app works - example: Jest -- DO use
--save-dev
because this package is just for unit testing; it should not be in the build output; an app works without this
- example: React -- DON'T use
- common practice is to use this flag unless you need the package included in the build output
-
--save-exact
flag -- my personal recommendation:-
always use this flag when installing NPM packages (lock versions down--avoid surprises)
- this flag ensures that the exact versions of NPM packages are captured in the lock file
- the above example command which installs Jest, ensures the following will be in the the lock file
- the exact version of Jest (version 27.0.6)
- ALSO the exact version of every dependency that Jest uses (the full tree of dependencies)
- NOTE: in the above example command which installs Jest
- WITHOUT the
--save-exact
flag in that command- the exact version of Jest (version 27.0.6) would be in the lock file
- but the versions of the tree of dependencies would NOT be exact
- WITHOUT the
-
always use this flag when installing NPM packages (lock versions down--avoid surprises)
- NPM command:
-
IMPORTANT:
- NPM command:
npm ci
- this command is mainly intended for continuous integration
- also, after cloning a repository, use this NPM command to download an EXACT copy of the full dependency tree based on this lock file
- doing this will ensure that all developers are developing off of the same dependency tree
- NPM command:
- regex search for detecting non-exact semantic version references in package-lock
- this is a helpful PR step--if i'm on a team that has agreed to lock down exact package versions
- semantic versioning: https://docs.npmjs.com/about-semantic-versioning
- convenient semantic versioning calculator: https://semver.npmjs.com/
- use the Visual Studio find feature with regex to search for this exact text value:
"version": ((".{1}")|("(\^|~).*")|(".*(x|\*).*")|("[0-9]\.[0-9]")),?
- NOTE: this regex works as of the current LTS version of Node.js and its version of NPM
- later versions of Node.js and NPM at some point (not sure which version) begin using a different format for the package-lock file
- searching for that value in a git diff file should show zero results
- if it does show matches, the matches are places where a NON-exact version of a package is set
- that pattern will match all the following examples EXCEPT the first 2
- the first 2 are good--they are examples of exact versions--the rest are non-exact
"version": "7.14.5", "version": "1.0.0", "version": "^7.14.5", "version": "~7.14.5", "version": "1.x.0", "version": "1.*.0", "version": "1.2.x", "version": "1.2.*", "version": "1.x", "version": "1.0", "version": "1.2", "version": "1", "version": "5", "version": "*", "version": "x",
Webpack is a highly configurable JavaScript module bundler (just a few configuration options listed here), and it can integrate numerous other tools into the build process.
webpack.config.js
- Webpack is a module bundler--at a high level, it
- crawls the modules
- traces the tree of module dependencies
- outputs a bundle file for the browser to download
-
"entry"
key- configures the first file webpack should start with--this should be a root module
- can have more than one--webpack recommends to have no more than one per web page
-
"output"
key- configures the output of Webpack's bundling process--location, name, etc.
- each entry has a corresponding output
-
"output.library"
key- [optional feature] configures how webpack exposes the output bundle
- example:
- name: "ClientApp"
- type: "var"
- example result: a variable
ClientApp
is attached to the global scope
- example:
- [optional feature] configures how webpack exposes the output bundle
-
"optimization"
key- configures ways to optimize the bundle output
- Webpack performs most of the needed optimization steps automatically based on the
mode
- e.g. when mode is "production", Webpack performs minification steps
-
"module"
key- uses
rules
to configure handling of files-
"test"
key - determines the matching files for a rule to process- note about JSX:
- babel can process JSX regardless of using a pattern that matches files with the .jsx extension
- JSX is legal in files with .js extension
- note about JSX:
-
"exclude"
key - identifies folder/files to exclude -
"loader"
key - tells Webpack what loader to use (e.g."babel-loader"
)
-
- example usage: configure Webpack to use Babel to transpile matching files
- uses
-
"resolve.extensions"
key- configure the file extensions that Webpack will automatically resolve
- ES6 import statements don't have to include file extensions
- either provide the file extension in the import statement, or put the file extension here for automatic resolution
- there is a default supported extensions list (here)
- note about JSX:
- babel compiles JSX, not Webpack--Webpack uses the babel loader to compile JSX
- including the .jsx extension in this list simply tells Webpack to look for these files when resolving module references
- JSX is legal in files with .js extension
-
"devtool"
key- configures the type of source map assets to produce
Babel is a highly configurable transpilation tool.
babel.config.js
- this file is optional--it configures Babel behavior
-
"presets"
key- tells Babel to use certain pre-determined configuration settings
- e.g.
"@babel/preset-env"
- settings to support transpiling latest JavaScript syntax while supporting multiple browsers and environments
- e.g.
"@babel/preset-react"
- settings to support transpiling JSX
- e.g.
"@babel/preset-typescript"
- settings to support transpiling TypeScript
- note:
- these presets can be set directly within Webpack in the module.rules loader
- putting the presets in the
babel.config
file makes this babel configuration available to any tool using babel- e.g. need ES6 modules to be transpiled by Babel for BOTH Webpack builds and Jest builds?
- keep the separate
babel.config
file so this configuration can be used by both- Webpack builds will use that Babel config while building a web bundle
- Jest builds will use that Babel config while building for a suite of tests
- keep the separate
- e.g. need ES6 modules to be transpiled by Babel for BOTH Webpack builds and Jest builds?
tsc is another transpilation tool specifically for TypeScript.
- Babel can transpile TypeScript, but it cannot perform type-checking or generate declaration (
d.ts
) files - tsc must be used for type-checking and generating declaration files
-
tsconfig.json
-
"emitDeclarationOnly"
key- tsc typically generates JavaScript files resulting from the transpilation of the TypeScript files
- this setting tells tsc to only generate declaration files
- a similar setting is noEmit--which tells tsc to not generate any files
- this setting and noEmit are for scenarios where you want tsc for type-checking and another tool (e.g. Babel) for transpilation
-
"isolatedModules"
key- an important setting when planning to use Babel for transpiling TypeScript
- tells tsc to warn about the existence of TypeScript features that cannot be interpreted properly in a single-file transpilation process
- more information here: https://www.typescriptlang.org/tsconfig#isolatedModules
-
- documentation on the above keys and others in the tsconfig.json file
Node Version Manager (NVM)
- there is a version that works on POSIX-compliant shells
- github source: https://github.com/nvm-sh/nvm
- and there is a Windows version
- github source: https://github.com/coreybutler/nvm-windows
- Microsoft Source: https://docs.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-windows
- this source contains a link to the github repo for NVM for windows
- this source shows the basic nvm commands to use
- NVM for windows github repo: https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows
- note: if you already have a version of Node.js installed the NVM install process will detect it and ask if it should control that version
- why:
- this tool makes installing and uninstalling multiple versions of Node.js super easy
-
this tool makes it easy to switch between different installed versions of Node.js
- this was REALLY helpful while i was exploring this issue:
- Node.JS version-specific issue (versions AFTER latest LTS--after 14.18.1) when running webpack:
- NOTE: when using the LTS version of Node.js, this was NOT an issue--only in later versions
- "Error : error : 0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19)"
-
https://github.com/webpack/webpack/issues/14532
- the comment with fix: https://github.com/webpack/webpack/issues/14532#issuecomment-950198249
- fix:
- use the following in package.json scripts --
SET NODE_OPTIONS=--openssl-legacy-provider
- use the following in package.json scripts --
- example:
"dev": "npm run typescheck && SET NODE_OPTIONS=--openssl-legacy-provider && webpack --mode=development",
- is this "fix" a security issue?? i don't think so, because webpack is just using the hash algorithm during optimization--not fur security