generator-azure-web-app
Version:
Minimalist Web App generator: Webpack/Rollup + React + Express, deployable to vanilla Node.js, Azure App Service, and IIS
145 lines (108 loc) • 8.71 kB
Markdown
# Advanced topics
This section helps you to dig deeper into the project.
## Important files and directories
| Filename | Description |
|----------------|-------------|
| `dist/` | Build output |
| `dist/website/` | Compiled web server ready to run by itself or hosted on IIS |
| `dist/website/public/` | Bundled content and static assets |
| `dist/packages/web.zip` | Web server packed by MSDeploy and ready to deploy to Azure Web Apps |
| [`src/app.js`](src/app.js) | Depends on `NODE_ENV`, development mode serves content directly from [`web/`](web/), production mode serves content from `dist/website/public` |
| [`src/controllers/api.js`](src/controllers/api.js) | RESTful API hosted at [http://localhost/api](http://localhost/api) |
| [`src/iisnode.yml`](src/iisnode.yml) | [iisnode configuration](https://tomasz.janczuk.org/2012/05/yaml-configuration-support-in-iisnode.html) |
| [`src/web.config`](src/web.config) | `Web.config` for hosting under Azure Web App and IIS |
| [`scripts/`](scripts) | Gulpfile for building and packing the project |
| [`web/files/`](web/files) | Asset source files |
| [`web/src/`](web/src) | JavaScript source files |
## NPM scripts
To help building the project, there are several NPM scripts.
| Task name | Description |
| ------------- | ----------- |
| `build` | Start the build process |
| `deploy` | Deploy the website to Azure Web App |
| `host:dev` | Host a Webpack development server and bundle on-the-fly |
| `host:prod` | Host a production server using pre-bundled files at `dist/website/` |
| `pack` | Use MSDeploy to pack everything at `dist/website/` into `dist/packages/web.zip` |
## Building the website
To build the website, run `npm run build`. The build output will be located at `dist/website/`.
* Specify build favor by either
* Set environment variable `NODE_ENV` to `production`, or
* Run `npm run build -- --build production`
* Specify bundler by either
* Set environment variable `BUNDLER` to `rollup` or `webpack`, or
* Run `npm run build -- --bundler rollup`
> Currently, the build favor (either `development` or `production`) is only used by [`transform-node-env-inline`](https://babeljs.io/docs/plugins/transform-node-env-inline/). It helps reducing bundle size by excluding developer-friendly error messages in production build.
### What the build do
Source code can be found at [`scripts/build.js`](scripts/build.js).
* Copy server code from [`src/`](src) to `dist/website/`, exclude `node_modules` folder
* After copy complete, will run `npm install --ignore-scripts --only=production` to install fresh packages
* Bundle source files from [`web/src/`](web/src) to `dist/website/public/dist/bundle.js`
* Will use existing npm packages from `web/node_modules`
* Copy static assets from [`web/files/`](web/files) to `dist/website/public/`
* Will minify image with [`gulp-imagemin`](https://www.npmjs.com/package/gulp-imagemin/)
* Will minify HTML with [`gulp-htmlmin`](https://www.npmjs.com/package/gulp-htmlmin/)
## Webpack configuration
The configuration file is located at [`web/webpack.config.js`](web/webpack.config.js). It controls how files are getting bundled into a monolithic `dist/website/public/js/bundle.js`.
* [`web/src/*.js`](web/src) and [`web/src/*.jsx`](web/src)
* Bundled by [`babel-loader`](https://www.npmjs.com/package/babel-loader)
* Enable React JSX by [`preset-react`](https://babeljs.io/docs/plugins/preset-react/)
* Enable ES2015 by [`preset-es2015`](http://babeljs.io/docs/plugins/preset-es2015/)
* Escape ES3 reserved keywords
* [`transform-es3-member-expression-literals`](https://babeljs.io/docs/plugins/transform-es3-member-expression-literals/)
* [`transform-es3-property-literals`](https://babeljs.io/docs/plugins/transform-es3-property-literals/)
* Transform `process.env.NODE_ENV` into `"development"` or `"production"` with [`transform-node-env-inline`](https://babeljs.io/docs/plugins/transform-node-env-inline/)
* Entrypoint is [`web/src/index.js`](web/src/index.js)
* [`web/src/*.css`](web/src) and [`web/src/*.less`](web/src)
* Bundled by [`less-loader`](https://www.npmjs.com/package/less-loader), then
* [`css-loader`](https://www.npmjs.com/package/css-loader), then
* [`style-loader`](https://www.npmjs.com/package/style-loader)
> We use rollup.js for bundling in production build. Since rollup.js currently only support single entrypoint and not code-splitting. If you want to enable these features, please build with `--bundler webpack` to use Webpack as bundler in production build.
## Webpack development mode configuration
When running Webpack development server, additional configurations are required, for example, hot module replacement.
When running under development server, we will add the following to [`webpack.config.js`](web/webpack.config.js):
* Serve assets from [`web/files/`](web/files/)
* Enable [source map](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-tools)
* Use absolute path for source map for compatibility with Edge
* Also write a copy of `bundle.js` to `dist/webpack/bundle.js` for debugging purpose
* Hot module replacement
* Support React component with [`react-hot`](https://github.com/gaearon/react-hot-loader) loader
## Rollup.js configuration
The configuration file is located at [`web/rollup.config.js`](web/rollup.config.js). It is similar to Webpack configuration.
* TBD: ~~[`web/src/*.less`](web/src)~~
* ~~Bundled by [`rollup-plugin-less`](https://npmjs.com/package/rollup-plugin-less)~~
* ~~Inject CSS styles into `<head>`~~
* [`web/src/*.js`](web/src)
* Bundled by [`rollup-plugin-babel`](https://www.npmjs.com/package/rollup-plugin-babel)
* Enable ES2015 with [`preset-es2015`](http://babeljs.io/docs/plugins/preset-es2015/)
* Enable React JSX with [`preset-react`](https://babeljs.io/docs/plugins/preset-react/)
* Escape ES3 reserved keywords
* [`transform-es3-member-expression-literals`](https://babeljs.io/docs/plugins/transform-es3-member-expression-literals/)
* [`transform-es3-property-literals`](https://babeljs.io/docs/plugins/transform-es3-property-literals/)
* Entrypoint is [`web/src/index.js`](web/src/index.js)
* Bundled by [`rollup-plugin-commonjs`](https://www.npmjs.com/package/rollup-plugin-commonjs)
* Convert CommonJS `require` statement into ES2015 `import` statement, including [`fbjs`](https://npmjs.com/package/fbjs), [`object-assign`](https://npmjs.com/package/object-assign), [`react`](https://npmjs.com/package/react), and [`react-dom`](https://npmjs.com/package/react-dom)
* Bundled by [`rollup-plugin-replace`](https://www.npmjs.com/package/rollup-plugin-replace)
* String-replace `process.env.NODE_ENV` into `"development"` or `"production"`
* Bundled by [`rollup-plugin-node-resolve`](https://www.npmjs.com/package/rollup-plugin-node-resolve)
* Bundle dependencies into `bundle.js`
## Enable source map output in production mode
Run `npm run build -- --sourcemap true` to output `dist/website/public/js/bundle.js.map` for debugging purpose.
## Packing with MSDeploy
To pack the content and production server, `npm run pack`.
It will create a MSDeploy ZIP file that can be deployed to any IIS server, including [Azure Web App](https://azure.microsoft.com/en-us/services/app-service/web/). This ZIP file contains Express server code and website contents in production favor.
Additional parameters added to MSDeploy ZIP file:
| name | defaultValue | tags | kind | scope |
|--------------------------|--------------------|----------|----------------|----------|
| IIS Web Application Name | `Default Web Site` | `IisApp` | `ProviderPath` | `IisApp` |
Before packing the project, make sure your current build is up-to-date, or run `npm run build`.
> [MSDeploy](https://www.iis.net/downloads/microsoft/web-deploy) is only supported on Windows.
## iisnode configuration
We have overrode some defaults in [`iisnode.yml`](iisnode.yml).
* `debuggingEnabled` is set to `false`
* `devErrorsEnabled` is set to `false`
* `loggingEnabled` is set to `false`
* `nodeProcessCountPerApplication` is set to `0`
* One worker process per CPU
* `node_env` is set to `production`
* We assume hosting the site in IIS is always in production mode
* Express is faster when environment variable `NODE_ENV` is set to `production`, details [here](http://apmblog.dynatrace.com/2015/07/22/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/)