Lab 5: Packages and Builds
- Due Nov 3, 2020 by 5:30pm
- Points 0
Attendance (2 min)
Sign in for credit.
Packages and Builds (5 min)
- Packages
- APIs, libraries, and frameworks that help you implement things rather than building stuff from scratch.
- The world of JavaScript packages is mostly dominated by npm Links to an external site., the Node Package Manager.
- There are millions of packages, some big, some small
- If you want to use any of them, you need to use npm.
- Builds
- While you can just write your application as a bunch of HTML, CSS, and JavaScript files, you'll find that working with packages is a lot easier if you bundle all of your code together for deployment.
- Additionally, if you're using non-JavaScript files that need to be translated into JavaScript files for deployment (e.g., JSX, TypeScript), you'll find it quite annoying to have to translate them every time you make an edit.
- Creating a build workflow is a way automate all of this bundling and translation. Builds define a process that takes all of your raw source files, do all of this translation, and prepare files suitable for deployment to a web server.
- The world of JavaScript is full of all kinds of technologies and solutions for defining builds, including Webpack Links to an external site., Grunt Links to an external site., and Gulp. Links to an external site. They're all powerful with somewhat steep learning curves.
Using npm for builds (10 min)
It is possible to use npm itself for basic builds. It includes a command line command run, which can define basic command line commands to run (e.g., "npm run myfancycommand"). Those commands, if simple, can be used to execute basic build activities.
Your instructor uses npm to build his faculty webpage. All of the logic for these builds is in his package.json file Links to an external site.. Here a simplified version that just focuses on the basics:
{
"name": "UWFacultyPage",
"version": "1.0.0",
"description": "The webpage for University of Washington professor Andy J. Ko.",
"license": "Creative Commons Attribution-NonCommercial 4.0 International",
"repository": "https://github.com/andyjko/faculty.git",
"scripts": {
"sayhi": "echo 'hi'",
"build": "browserify -t [ babelify --presets [ @babel/preset-env @babel/preset-react ] ] app.js | uglifyjs > build/app.js"
},
"devDependencies": {
"browserify": "^16.2",
"babelify": "^10",
"@babel/core": "^7",
"@babel/cli": "^7",
"@babel/preset-react": "^7",
"@babel/preset-env": "^7",
"uglify-js": "^3.4.7"
},
"dependencies": {
"bootstrap": "^3.3.7",
"jquery": "^3.0.0",
"lodash": "^4.17.10",
"npm": "^5.10.0",
"react": "^16.3",
"react-dom": "^16.3"
}
}
Let's walk through the details:
- The first five properties in in the file are just metadata for my web application. Your project should include relevant details for your project.
- the scripts property includes command line commands with the name of your choice. The example above includes to commands:
- The first one, which I named "sayhi", is just the Unix/Linux command "echo 'hi'", which just prints the string "hi" to the command line. I included this to show how commands really can be anything and can be named anything.
- The second one, which I'll explain in more detail below, is our build command. It could have been named "horse" or "tree" or "dostuff", I just named it "build".
- We can execute any of the scripts by running the command "npm run sayhi" or "npm run build" and npm will run the command on the command line.
- devDependencies specifies all of the npm packages needed to build the project. These are the commands we'll need to execute the scripts above. Each of the names in that list corresponds to an npm package on the npm website; each of the strings refers to the version, or versions, that the application requires to be build. This list includes browserify Links to an external site. (a way to include npm modules in JavaScript), babel Links to an external site. (a way of transforming the latest versions of JavaScript 6, TypeScript, JSX, or other JavaScript variants into JavaScript 5, so it can be executed in all browsers), babelify Links to an external site. (a hook to connect babel into browserify's module system), and uglify Links to an external site. (which minimizes the size of JavaScript source files by removing whitespace, renaming variables, making them faster to load).
- dependencies specifies all of the npm packages needed to for the web application to function. These are packages our source code will refer to. My website uses Bootstrap as a CSS framework, jQuery because Bootstrap requires it, lodash as a library of utility functions for simplifying data processing, React for views, and ReactDOM, a helper package for accessing the DOM in React components.
Now, let's discuss that gnarly, build script:
browserify -t [ babelify --presets [ @babel/preset-env @babel/preset-react ] ] app.js | uglifyjs > build/app.js
What's going on here?
- First, to understand this, you have to know how parse Bash shell commands. The first and impost important thing to notice is the vertical bar "|", which is called a "pipe". That means that the results of the command left of the pipe to the command on the right.
- The command on the left executes browserify.
- The -t tells browserify to use a "transform module" (in this case, babelify) to transform a "top-level" file into JavaScript, in this case the app.js file that is the root source file.
- As the documentation states, we can pass options between []'s to specify the transform module and what arguments to give the transform module. In this case, we're telling browserify to use the babelify transform module, and we're telling babelify to use the preset-env plugin to support JavaScript 6 syntax, and the preset-react plugin to support JSX syntax.
- All of this might seem like magic, and because of all of the ridiculous terminology, it basically is. The essential thing to understand is that the command left of the pipe translates JSX -> JavaScript 6 -> JavaScript 5 so it can be executed in any browser.
- The magic thing browserify does is take all of the JavaScript source files referred to in app.js, includes all of the npm packages they refer to, and bundles them into one huge single JavaScript file.
- The command on the right of the pipe executes uglify, which takes the big huge single JavaScript file made by browserify and removes all of its whitespace to shrink the file for faster loading.
- Lastly, the > symbol tells the Bash shell to take the minified JavaScript file and store it to disk in the file build.js. The result is that all of the source files in our project got translated into JS5, combined into a single file, then minified, then written to the file system. After this runs, we can load an HTML file that refers to this build.js file and all of our JavaScript will execute.
From a build perspective, this is a pretty simple build process. It basically just translates and combines a bunch of files. Your builds might be more complex, moving files around, copying images, running unit tests, etc. So the example above is about as simple as it gets for a basic React web application.
Setup your builds (25 min)
As a team, attempt to set up your builds following the example above. This may require:
- Installing npm on your machine.
- Deciding how you'll execute builds. If you'll run them on your local device and test on your local device, then you'll need to write builds commands that can execute on your device (e.g., if you use Windows, using it's default command line utilities, or installing a Windows Bash shell).
- Writing your package.json file.