Repository: phoenixframework/phoenix
Pull request #4247 (2021-03-08 18:18:19)

Bump elliptic from 6.5.2 to 6.5.4 in /assets
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.4.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/indutny/elliptic/commit/43ac7f230069bd1575e1e4a58394a512303ba803"><code>43ac7f2</code></a> 6.5.4</li>
<li><a href="https://github.com/indutny/elliptic/commit/f4bc72be11b0a508fb790f445c43534307c9255b"><code>f4bc72b</code></a> package: bump deps</li>
<li><a href="https://github.com/indutny/elliptic/commit/441b7428b0e8f6636c42118ad2aaa186d3c34c3f"><code>441b742</code></a> ec: validate that a point before deriving keys</li>
<li><a href="https://github.com/indutny/elliptic/commit/e71b2d9359c5fe9437fbf46f1f05096de447de57"><code>e71b2d9</code></a> lib: relint using eslint</li>
<li><a href="https://github.com/indutny/elliptic/commit/8421a01aa3ff789c79f91eaf8845558a7be2b9fa"><code>8421a01</code></a> build(deps): bump elliptic from 6.4.1 to 6.5.3 (<a href="https://github-redirect.dependabot.com/indutny/elliptic/issues/231">#231</a>)</li>
<li><a href="https://github.com/indutny/elliptic/commit/8647803dc3d90506aa03021737f7b061ba959ae1"><code>8647803</code></a> 6.5.3</li>
<li><a href="https://github.com/indutny/elliptic/commit/856fe4d99fe7b6200556e6400b3bf585b1721bec"><code>856fe4d</code></a> signature: prevent malleability and overflows</li>
<li>See full diff in <a href="https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.4">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=elliptic&package-manager=npm_and_yarn&previous-version=6.5.2&new-version=6.5.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/phoenixframework/phoenix/network/alerts).

</details>


Patch:
diff --git a/RELEASE.md b/RELEASE.md
index 052ee486d..1f9911a49 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -2,11 +2,14 @@
 
   1. Check related deps for required version bumps and compatibility (`phoenix_ecto`, `phoenix_pubsub_redis`, `phoenix_html`)
   2. Bump version in related files below
-  3. Run tests, commit, push code
-  4. Publish `phx_new` and `phoenix` packages and docs after pruning any extraneous uncommitted files
-  5. Test installer by generating a new app, running `mix deps.get`, and compiling
-  6. Publish to `npm` with `npm publish`
-  7. Start -dev version in related files below
+  3. Run tests:
+      - `mix test` in the root folder
+      - `mix test` in the `installer/` folder
+  4. Commit, push code
+  5. Publish `phx_new` and `phoenix` packages and docs after pruning any extraneous uncommitted files
+  6. Test installer by generating a new app, running `mix deps.get`, and compiling
+  7. Publish to `npm` with `npm publish`
+  8. Start -dev version in related files below
 
 ## Files with version
 
diff --git a/assets/package-lock.json b/assets/package-lock.json
index 3826b4a2f..ebbc2ab94 100644
--- a/assets/package-lock.json
+++ b/assets/package-lock.json
@@ -2665,7 +2665,7 @@
       "dependencies": {
         "acorn": {
           "version": "2.7.0",
-          "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
           "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=",
           "dev": true
         }
@@ -3208,12 +3208,6 @@
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
           "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
           "dev": true
-        },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
         }
       }
     },
@@ -4260,18 +4254,32 @@
       }
     },
     "elliptic": {
-      "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
-      "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+      "version": "6.5.4",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+      "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
       "dev": true,
       "requires": {
-        "bn.js": "^4.4.0",
-        "brorand": "^1.0.1",
+        "bn.js": "^4.11.9",
+        "brorand": "^1.1.0",
         "hash.js": "^1.0.0",
-        "hmac-drbg": "^1.0.0",
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0",
-        "minimalistic-crypto-utils": "^1.0.0"
+        "hmac-drbg": "^1.0.1",
+        "inherits": "^2.0.4",
+        "minimalistic-assert": "^1.0.1",
+        "minimalistic-crypto-utils": "^1.0.1"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.12.0",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+          "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+          "dev": true
+        },
+        "inherits": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+          "dev": true
+        }
       }
     },
     "emoji-regex": {
@@ -6146,7 +6154,7 @@
       "dependencies": {
         "acorn": {
           "version": "2.7.0",
-          "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
           "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=",
           "dev": true
         }
@@ -6880,7 +6888,7 @@
     },
     "minimist": {
       "version": "0.0.8",
-      "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
       "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
       "dev": true
     },
@@ -7145,12 +7153,6 @@
             "strip-ansi": "^5.0.0"
           }
         },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
-        },
         "yargs": {
           "version": "13.3.0",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
@@ -10453,12 +10455,6 @@
             "strip-ansi": "^5.0.0"
           }
         },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
-        },
         "yargs": {
           "version": "13.2.4",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
@@ -10596,7 +10592,7 @@
     },
     "wrap-ansi": {
       "version": "2.1.0",
-      "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
       "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
       "dev": true,
       "requires": {
@@ -10629,9 +10625,9 @@
       "dev": true
     },
     "y18n": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
+      "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==",
       "dev": true
     },
     "yargs": {
@@ -10881,12 +10877,6 @@
             "strip-ansi": "^5.0.0"
           }
         },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
-        },
         "yargs": {
           "version": "13.3.2",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
diff --git a/guides/.gitignore b/guides/.gitignore
deleted file mode 100644
index f4692f4fa..000000000
--- a/guides/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-.DS_Store
-/_build
-/deps
-/doc
-erl_crash.dump
-.sass-cache
-*.ez
-
diff --git a/guides/authentication/mix_phx_gen_auth.md b/guides/authentication/mix_phx_gen_auth.md
index bf8d8fd2e..a7134fd10 100644
--- a/guides/authentication/mix_phx_gen_auth.md
+++ b/guides/authentication/mix_phx_gen_auth.md
@@ -1,36 +1,46 @@
 # mix phx.gen.auth
 
-The `mix phx.gen.auth` command generates a flexible, pre-built authentication system into your phoenix app. This simple generator allows you to quickly move past the task of adding authentication to your codebase and stay focused on the real-world problem your application is trying to solve.
+The `mix phx.gen.auth` command generates a flexible, pre-built authentication system into your Phoenix app. This simple generator allows you to quickly move past the task of adding authentication to your codebase and stay focused on the real-world problem your application is trying to solve.
 
-## Getting Started
+## Getting started
 
 Let's start by running the following command from the root of our app (or `apps/my_app_web` in an umbrella app):
 
-    $ mix phx.gen.auth Accounts User users
+```console
+$ mix phx.gen.auth Accounts User users
+```
 
 This creates an `Accounts` context with an `Accounts.User` schema module. The final argument is the plural version of the schema module which is used for generating database table names and route helpers. The `mix phx.gen.auth` generator is similar to `mix phx.gen.html` except it does not accept a list of additional fields to add to the schema and it generates many more context functions.
 
-Since this generator installed additional dependencies in `mix.exs`, let's fetch those dependencies:
+Since this generator installed additional dependencies in `mix.exs`, let's fetch those:
 
-    $ mix deps.get
+```console
+$ mix deps.get
+```
 
 Now we need to verify the database connection details for the development and test environments in `config/` so the migrator and tests can run properly. Then run the following to create the database:
 
-    $ mix ecto.setup
+```console
+$ mix ecto.setup
+```
 
 Let's run the tests to make sure our new authentication system works as expected.
 
-    $ mix test
+```console
+$ mix test
+```
 
-And finally, let's start our phoenix server and try it out.
+And finally, let's start our Phoenix server and try it out.
 
-    $ mix phx.server
+```console
+$ mix phx.server
+```
 
-## Developer Responsibilities
+## Developer responsibilities
 
-Since phoenix generates this code into your application instead of building these modules into Phoenix itself, you now have complete freedom to modify the authentication system so it works best with your use case. The one caveat with using a generated authentication system is it will not be updated after it's been generated. Therefore as improvements are made to the output of `mix phx.gen.auth`, it becomes your responsibility to determine if these changes need to be ported into your application. Security-related and other important improvements will be explicitly and clearly marked in CHANGELOG and upgrade notes.
+Since Phoenix generates this code into your application instead of building these modules into Phoenix itself, you now have complete freedom to modify the authentication system so it works best with your use case. The one caveat with using a generated authentication system is it will not be updated after it's been generated. Therefore as improvements are made to the output of `mix phx.gen.auth`, it becomes your responsibility to determine if these changes need to be ported into your application. Security-related and other important improvements will be explicitly and clearly marked in the `CHANGELOG.md` file and upgrade notes.
 
-## Generated Code
+## Generated code
 
 The following are notes about the generated authentication system.
 
@@ -40,7 +50,7 @@ The password hashing mechanism defaults to `bcrypt` for Unix systems and `pbkdf2
 
 ### Forbidding access
 
-The generated code ships with an auth module with a handful of plugs that fetch the current user, require authentication and so on. For instance, in an app named Demo which had `mix phx.gen.auth Accounts User users` run on it, you will find a module named `DemoWeb.UserAuth` with plugs such as:
+The generated code ships with an authentication module with a handful of plugs that fetch the current user, require authentication and so on. For instance, in an app named Demo which had `mix phx.gen.auth Accounts User users` run on it, you will find a module named `DemoWeb.UserAuth` with plugs such as:
 
   * `fetch_current_user` - fetches the current user information if available
   * `require_authenticated_user` - must be invoked after `fetch_current_user` and requires that a current user exists and is authenticated
@@ -60,19 +70,21 @@ All sessions and tokens are tracked in a separate table. This allows you to trac
 
 Note that whenever the password changes (either via reset password or directly), all tokens are deleted and the user has to log in again on all devices.
 
-### Enumeration attacks
+### User Enumeration attacks
 
-An enumeration attack allows an attacker to enumerate all emails registered in the application. The generated authentication code protects against enumeration attacks on all endpoints, except in the registration and update email forms. If your application is really sensitive to enumeration attacks, you need to implement your own registration workflow, which tends to be very different from the workflow for most applications.
+A user enumeration attack allows an attacker to enumerate all emails registered in the application. For example, if trying to log in with a registered email and a wrong password returns a different error than trying to log in with an email that was never registered, an attacker could use this discrepency to find out which emails have accounts.
+
+The generated authentication code protects against enumeration attacks on all endpoints, except in the registration and update email forms. If your application is really sensitive to enumeration attacks, you need to implement your own registration workflow, which tends to be very different from the workflow for most applications.
 
 ### Case sensitiveness
 
 The email lookup is made to be case insensitive. Case insensitive lookups are the default in MySQL and MSSQL but use the [`citext` extension in PostgreSQL](https://www.postgresql.org/docs/current/citext.html).
 
-Note `citext` is part of Postgres itself and is bundled with it in most operating systems and package managers. `mix phx.gen.auth` takes care of creating the extension and no extra work is necessary in the majority of cases. If by any chance your package manager splits `citext` into a separate package, you will get an error while migrating and you can most likely solve it by installing the `postgres-contrib` package.
+Note `citext` is part of PostgreSQL itself and is bundled with it in most operating systems and package managers. `mix phx.gen.auth` takes care of creating the extension and no extra work is necessary in the majority of cases. If by any chance your package manager splits `citext` into a separate package, you will get an error while migrating and you can most likely solve it by installing the `postgres-contrib` package.
 
 ### Concurrent tests
 
-The generated tests run concurrently if you are using a database that supports concurrent tests (Postgres).
+The generated tests run concurrently if you are using a database that supports concurrent tests, which is the case of PostgreSQL.
 
 ## Additional resources
 
@@ -80,8 +92,8 @@ The following links have more information regarding the motivation and design of
 
   * José Valim's blog post - [An upcoming authentication solution for Phoenix](https://dashbit.co/blog/a-new-authentication-solution-for-phoenix)
   * The [original `phx_gen_auth` repo][phx_gen_auth repo] (for Phoenix 1.5 applications) - This is a great resource to see discussions around decisions that have been made in earlier versions of the project.
-  * [Original pull request on bare phoenix app][auth pr]
+  * [Original pull request on bare Phoenix app][auth PR]
   * [Original design spec](https://github.com/dashbitco/mix_phx_gen_auth_demo/blob/auth/README.md)
 
 [phx_gen_auth repo]: https://github.com/aaronrenner/phx_gen_auth
-[auth pr]: https://github.com/dashbitco/mix_phx_gen_auth_demo/pull/1
+[auth PR]: https://github.com/dashbitco/mix_phx_gen_auth_demo/pull/1
diff --git a/guides/contexts.md b/guides/contexts.md
index 52a53fa9e..ebe525317 100644
--- a/guides/contexts.md
+++ b/guides/contexts.md
@@ -378,7 +378,8 @@ Next, let's expose our new feature to the web by adding the credentials input to
 +   <% end %>
 + </div>
 
-  <%= submit "Submit" %>
+  <div>
+    <%= submit "Save" %>
 ```
 
 We used `Phoenix.HTML`'s `inputs_for` function to add an associations nested fields within the parent form. Within the nested inputs, we rendered our credential's email field and included the `label` and `error_tag` helpers just like our other inputs.
diff --git a/guides/deployment/releases.md b/guides/deployment/releases.md
index d61805d58..c83643f95 100644
--- a/guides/deployment/releases.md
+++ b/guides/deployment/releases.md
@@ -37,11 +37,11 @@ Then load dependencies to compile code and assets:
 $ mix deps.get --only prod
 $ MIX_ENV=prod mix compile
 
-# Install / update  JavaScript dependencies
-$ npm install --prefix ./assets
+# Install / update JavaScript dependencies
+$ npm install --prefix assets
 
 # Compile assets
-$ npm run deploy --prefix ./assets
+$ npm run deploy --prefix assets
 $ MIX_ENV=prod mix phx.digest
 ```
 
@@ -172,7 +172,7 @@ FROM node:15.7.0-alpine3.10 as assets
 
 # install build dependencies
 RUN --mount=type=cache,sharing=locked,target=/var/cache/apk \
-    apk add build-base python
+    apk add build-base python3
 
 # prepare build dir
 WORKDIR /app
@@ -245,3 +245,4 @@ A few points about configuring a containerized application:
 
 - If you run your app in a container, the `Endpoint` needs to be configured to listen on a "public" `:ip` address (like `0.0.0.0.0.0.0.0`) so that the app can be reached from outside the container. Whether the host should publish the container's ports to its own public IP or to localhost depends on your needs.
 - The more configuration you can provide at runtime (using `config/runtime.exs`), the more reusable your images will be across environments. In particular, secrets like database credentials and API keys should not be compiled into the image, but rather should be provided when creating containers based on that image. This is why the `Endpoint`'s `:secret_key_base` is configured in `config/runtime.exs` by default.
+- If possible, any environment variables that are needed at runtime should be read in `config/runtime.exs`, not scattered throughout your code. Having them all visible in one place will make it easier to ensure the containers get what they need, especially if the person doing the infrastructure work does not work on the Elixir code. Libraries in particular should never directly read environment variables; all their configuration should be handed to them by the top-level application, preferably [without using the application environment](https://hexdocs.pm/elixir/library-guidelines.html#avoid-application-configuration).
diff --git a/guides/directory_structure.md b/guides/directory_structure.md
index d678f78bc..7ae4ede90 100644
--- a/guides/directory_structure.md
+++ b/guides/directory_structure.md
@@ -20,19 +20,19 @@ When we use `mix phx.new` to generate a new Phoenix application, it builds a top
 
 We will go over those directories one by one:
 
-  * `_build` - a directory created by the `mix` command line tool that ships as part of Elixir that holds all compilation artifacts. As we have seen in "[Up and Running](up_and_running.html)", `mix` is the main interface to your application. We use Mix to compile our code, create databases, run our server, and more. This directory must not be checked into version control and it can be removed at any time. Removing it will force Mix to rebuild your application from scratch
+  * `_build` - a directory created by the `mix` command line tool that ships as part of Elixir that holds all compilation artifacts. As we have seen in "[Up and Running](up_and_running.html)", `mix` is the main interface to your application. We use Mix to compile our code, create databases, run our server, and more. This directory must not be checked into version control and it can be removed at any time. Removing it will force Mix to rebuild your application from scratch.
 
-  * `assets` - a directory that keeps everything related to front-end assets, such as JavaScript, CSS, static images and more. It is typically handled by the `npm` tool. Phoenix developers typically only need to run `npm install` inside the assets directory. Everything else is managed by Phoenix
+  * `assets` - a directory that keeps everything related to front-end assets, such as JavaScript, CSS, static images and more. It is typically handled by the `npm` tool. Phoenix developers typically only need to run `npm install` inside the assets directory. Everything else is managed by Phoenix.
 
-  * `config` - a directory that holds your project configuration. The `config/config.exs` file is the main entry point for your configuration. At the end of the `config/config.exs`, it imports environment specific configuration, which can be found in `config/dev.exs`, `config/test.exs`, and `config/prod.exs`
+  * `config` - a directory that holds your project configuration. The `config/config.exs` file is the main entry point for your configuration. At the end of the `config/config.exs`, it imports environment specific configuration, which can be found in `config/dev.exs`, `config/test.exs`, and `config/prod.exs`.
 
-  * `deps` - a directory with all of our Mix dependencies. You can find all dependencies listed in the `mix.exs` file, inside the `def deps do` function definition. This directory must not be checked into version control and it can be removed at any time. Removing it will force Mix to download all deps from scratch
+  * `deps` - a directory with all of our Mix dependencies. You can find all dependencies listed in the `mix.exs` file, inside the `def deps do` function definition. This directory must not be checked into version control and it can be removed at any time. Removing it will force Mix to download all deps from scratch.
 
-  * `lib` - a directory that holds your application source code. This directory is broken into two subdirectories, `lib/hello` and `lib/hello_web`. The `lib/hello` directory will be responsible to host all of your business logic and business domain. It typically interacts directly with the database - it is the "Model" in Model-View-Controller (MVC) architecture. `lib/hello_web` is responsible for exposing your business domain to the world, in this case, through a web application. It holds both the View and Controller from MVC. We will discuss the contents of these directories with more detail in the next sections
+  * `lib` - a directory that holds your application source code. This directory is broken into two subdirectories, `lib/hello` and `lib/hello_web`. The `lib/hello` directory will be responsible to host all of your business logic and business domain. It typically interacts directly with the database - it is the "Model" in Model-View-Controller (MVC) architecture. `lib/hello_web` is responsible for exposing your business domain to the world, in this case, through a web application. It holds both the View and Controller from MVC. We will discuss the contents of these directories with more detail in the next sections.
 
-  * `priv` - a directory that keeps all assets that are necessary in production but are not directly part of your source code. You typically keep database scripts, translation files, and more in here
+  * `priv` - a directory that keeps all assets that are necessary in production but are not directly part of your source code. You typically keep database scripts, translation files, and more in here.  Built static assets, sourced from the `assets` directory, are also served from here by default.
 
-  * `test` - a directory with all of our application tests. It often mirrors the same structure found in `lib`
+  * `test` - a directory with all of our application tests. It often mirrors the same structure found in `lib`.
 
 ## The lib/hello directory
 
@@ -113,3 +113,13 @@ Besides the directories mentioned, `lib/hello_web` has four files at its root. `
 Through _Telemetry_, Phoenix is able to collect metrics and send monitoring events of your application. The `lib/hello_web/telemetry.ex` file defines the supervisor responsible for managing the telemetry processes. You can find more information on this topic in the [Telemetry guide](telemetry.html).
 
 Finally, there is a `lib/hello_web/gettext.ex` file which provides internationalization through [Gettext](https://hexdocs.pm/gettext/Gettext.html). If you are not worried about internationalization, you can safely skip this file and its contents.
+
+## The assets directory
+
+The `assets` directory contains everything related to front-end assets, such as JavaScript, CSS, static images and more. It is typically handled by the [npm] tool. Phoenix developers typically only need to run `npm install` inside the assets directory. Everything else is managed by Phoenix.
+
+A **default** Phoenix application includes a `webpack.config.js` capable of processing your front-end assets and staging them in the `priv/static` folder, where they may be served by the [Plug.Static] plug configured in `lib/hello_web/endpoint.ex`.  When running in dev mode (`MIX_ENV=dev`), Phoenix watches for any changes you make in the `assets` directory, and then takes care of updating your front end application in your browser as you work.
+
+**NB:** When you first create your Phoenix app using `mix phx.new` it is possible to specify options that will affect the presence and layout of the `assets` directory.  In fact Phoenix apps don't require you have a front-end at all (handy if you're writing an API for example).  For more information you can run `mix help phx.new` or see the documentation in [Mix tasks](mix_tasks.html).
+
+[npm]: https://www.npmjs.com/package/npm
diff --git a/guides/ecto.md b/guides/ecto.md
index 1d0628dc4..271224950 100644
--- a/guides/ecto.md
+++ b/guides/ecto.md
@@ -532,10 +532,7 @@ defmodule HelloPhoenix.MixProject do
       {:phoenix_ecto, "~> 4.0"},
       {:ecto_sql, "~> 3.5"},
       {:myxql, ">= 0.0.0"},
-      {:phoenix_html, "~> 2.11"},
-      {:phoenix_live_reload, "~> 1.2", only: :dev},
-      {:gettext, "~> 0.11"},
-      {:plug_cowboy, "~> 2.0"}
+      ...
     ]
   end
 end
diff --git a/guides/howto/custom_error_pages.md b/guides/howto/custom_error_pages.md
index 9cde4b8fc..ccdb43d93 100644
--- a/guides/howto/custom_error_pages.md
+++ b/guides/howto/custom_error_pages.md
@@ -54,9 +54,9 @@ Great, so we have this `template_not_found/2` function that takes a template and
 In other words, to provide custom error pages, we could simply define a proper `render/2` function clause in `HelloWeb.ErrorView`.
 
 ```elixir
-def render("404.html", _assigns) do
-  "Page Not Found"
-end
+  def render("404.html", _assigns) do
+    "Page Not Found"
+  end
 ```
 
 But we can do even better.
@@ -96,6 +96,14 @@ Phoenix generates an `ErrorView` for us, but it doesn't give us a `lib/hello_web
 </html>
 ```
 
+After you define the template file, remember to remove the equivalent `render/2` clause for that template, as otherwise the function overrides the template. Let's do so for the 404.html clause we have previously introduced in `lib/hello_web/views/error_view.ex`:
+
+```diff
+- def render("404.html", _assigns) do
+-  "Page Not Found"
+- end
+```
+
 Now when we go back to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path), we should see a much nicer error page. It is worth noting that we did not render our `404.html.eex` template through our application layout, even though we want our error page to have the look and feel of the rest of our site. This is to avoid circular errors. For example, what happens if our application failed due to an error in the layout? Attempting to render the layout again will just trigger another error. So ideally we want to minimize the amount of dependencies and logic in our error templates, sharing only what is necessary.
 
 ## Custom exceptions
diff --git a/guides/introduction/installation.md b/guides/introduction/installation.md
index 5333ccefe..233060716 100644
--- a/guides/introduction/installation.md
+++ b/guides/introduction/installation.md
@@ -9,7 +9,7 @@ In order to build a Phoenix application, we will need a few dependencies install
 
 Please take a look at this list and make sure to install anything necessary for your system. Having dependencies installed in advance can prevent frustrating problems later on.
 
-## Elixir 1.6 or later
+## Elixir 1.9 or later
 
 Phoenix is written in Elixir, and our application code will also be written in Elixir. We won't get far in a Phoenix app without it! The Elixir site maintains a great [Installation Page](https://elixir-lang.org/install.html) to help.
 
@@ -21,23 +21,23 @@ Here's the command to install Hex (If you have Hex already installed, it will up
 $ mix local.hex
 ```
 
-## Erlang 20 or later
+## Erlang 22 or later
 
 Elixir code compiles to Erlang byte code to run on the Erlang virtual machine. Without Erlang, Elixir code has no virtual machine to run on, so we need to install Erlang as well.
 
 When we install Elixir using instructions from the Elixir [Installation Page](https://elixir-lang.org/install.html),  we will usually get Erlang too. If Erlang was not installed along with Elixir, please see the [Erlang Instructions](https://elixir-lang.org/install.html#installing-erlang) section of the Elixir Installation Page for instructions.
 
-> A note about Erlang and Phoenix: while Phoenix itself only requires Erlang 20 or later, one of Phoenix's dependencies, [cowboy](https://github.com/ninenines/cowboy), depends on Erlang 22 or later since cowboy 2.8.0. It is recommended to either install Erlang 22 or add `{:cowboy, "~> 2.7.0"}` to your mix.exs once your app has been created.
+> A note about Erlang and Phoenix: while Phoenix itself only requires Erlang 21 or later, one of Phoenix's dependencies, [cowboy](https://github.com/ninenines/cowboy), depends on Erlang 22.
 
 ## Phoenix
 
-To check that we are on Elixir 1.6 and Erlang 20 or later, run:
+To check that we are on Elixir 1.9 and Erlang 22 or later, run:
 
 ```console
 elixir -v
-Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
+Erlang/OTP 22 [erts-10.7] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
 
-Elixir 1.6.3
+Elixir 1.9.1
 ```
 
 Once we have Elixir and Erlang, we are ready to install the Phoenix application generator:
diff --git a/guides/introduction/up_and_running.md b/guides/introduction/up_and_running.md
index 81ec05808..535546c34 100644
--- a/guides/introduction/up_and_running.md
+++ b/guides/introduction/up_and_running.md
@@ -10,7 +10,7 @@ We can run `mix phx.new` from any directory in order to bootstrap our Phoenix ap
 $ mix phx.new hello
 ```
 
-> A note about [webpack](https://webpack.js.org/) before we begin: Phoenix will use webpack for asset management by default. Webpack's dependencies are installed via the node package manager, not mix. Phoenix will prompt us to install them at the end of the `mix phx.new` task. If we say "no" at that point, and if we don't install those dependencies later with `npm install`, our application will raise errors when we try to start it, and our assets may not load properly. If we don't want to use webpack at all, we can simply pass `--no-webpack` to `mix phx.new`.
+> A note about [webpack](https://webpack.js.org/) before we begin: Phoenix will use webpack for asset management by default. Webpack's dependencies are installed via the node package manager, not mix. Phoenix will prompt us to install them at the end of the `mix phx.new` task. If we say "no" at that point, and if we don't install those dependencies later with `npm install --prefix assets`, our application will raise errors when we try to start it, and our assets may not load properly. If we don't want to use webpack at all, we can simply pass `--no-webpack` to `mix phx.new`.
 
 > A note about [Ecto](ecto.html): Ecto allows our Phoenix application to communicate with a data store, such as PostgreSQL, MySQL, and others. If our application will not require this component we can skip this dependency by passing the `--no-ecto` flag to `mix phx.new`. This flag may also be combined with `--no-webpack` to create a skeleton application.
 
diff --git a/guides/mix_tasks.md b/guides/mix_tasks.md
index 5052e7a21..b65f325ad 100644
--- a/guides/mix_tasks.md
+++ b/guides/mix_tasks.md
@@ -1,13 +1,13 @@
-# Mix Tasks
+# Mix tasks
 
-There are currently a number of built-in Phoenix-specific and Ecto-specific mix tasks available to us within a newly-generated application. We can also create our own application specific tasks.
+There are currently a number of built-in Phoenix-specific and Ecto-specific [Mix tasks](`Mix.Task`) available to us within a newly-generated application. We can also create our own application specific tasks.
 
 > Note to learn more about `mix`, you can read Elixir's official [Introduction to Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html).
 
 ## Phoenix tasks
 
 ```console
-➜ mix help --search "phx"
+$ mix help --search "phx"
 mix local.phx          # Updates the Phoenix project generator locally
 mix phx                # Prints Phoenix help information
 mix phx.digest         # Digests and compresses static files
@@ -35,7 +35,7 @@ We will cover all Phoenix Mix tasks, except `phx.new`, `phx.new.ecto`, and `phx.
 
 ### `mix phx.gen.html`
 
-Phoenix offers the ability to generate all the code to stand up a complete HTML resource - ecto migration, ecto context, controller with all the necessary actions, view, and templates. This can be a tremendous time saver. Let's take a look at how to make this happen.
+Phoenix offers the ability to generate all the code to stand up a complete HTML resource — Ecto migration, Ecto context, controller with all the necessary actions, view, and templates. This can be a tremendous time saver. Let's take a look at how to make this happen.
 
 The `mix phx.gen.html` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization.
 
@@ -57,7 +57,7 @@ $ mix phx.gen.html Blog Post posts body:string word_count:integer
 * injecting test/hello/blog/blog_test.exs
 ```
 
-When `mix phx.gen.html` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations.
+When `mix phx.gen.html` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our Ecto migrations.
 
 ```console
 Add the resource to your browser scope in lib/hello_web/router.ex:
@@ -101,7 +101,7 @@ Add the resource to your browser scope in lib/hello_web/router.ex:
     resources "/posts", PostController
 ```
 
-Similarly - if we want a context created without a schema for our resource we can use the `--no-schema` flag.
+Similarly, if we want a context created without a schema for our resource we can use the `--no-schema` flag.
 
 ```console
 $ mix phx.gen.html Blog Post posts body:string word_count:integer --no-schema
@@ -123,7 +123,7 @@ It will tell us we need to add a line to our router file, but since we skipped t
 
 ### `mix phx.gen.json`
 
-Phoenix also offers the ability to generate all the code to stand up a complete JSON resource - ecto migration, ecto schema, controller with all the necessary actions and view. This command will not create any template for the app.
+Phoenix also offers the ability to generate all the code to stand up a complete JSON resource — Ecto migration, Ecto schema, controller with all the necessary actions and view. This command will not create any template for the app.
 
 The `mix phx.gen.json` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization.
 
@@ -142,7 +142,7 @@ $ mix phx.gen.json Blog Post posts title:string content:string
 * injecting test/hello/blog/blog_test.exs
 ```
 
-When `mix phx.gen.json` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations.
+When `mix phx.gen.json` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our Ecto migrations.
 
 ```console
 Add the resource to your :api scope in lib/hello_web/router.ex:
@@ -168,7 +168,7 @@ warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private
 
 ### `mix phx.gen.context`
 
-If we don't need a complete HTML/JSON resource and instead are only interested in a context, we can use the `mix phx.gen.context` task. It will generate a context, a schema, a migration and a test case.
+If we don't need a complete HTML/JSON resource and only need a context, we can use the `mix phx.gen.context` task. It will generate a context, a schema, a migration and a test case.
 
 The `mix phx.gen.context` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes.
 
@@ -207,7 +207,7 @@ $ mix phx.gen.schema Accounts.Credential credentials email:string:unique user_id
 
 ### `mix phx.gen.auth`
 
-Phoenix also offers the ability to generate all of the code to stand up a complete authentication system - ecto migration, phoenix context, controllers, templates, etc. This can be a huge time saver, allowing you to quickly add authentication to your system and shift your focus back to the primary problems your application is trying to solve.
+Phoenix also offers the ability to generate all of the code to stand up a complete authentication system — Ecto migration, phoenix context, controllers, templates, etc. This can be a huge time saver, allowing you to quickly add authentication to your system and shift your focus back to the primary problems your application is trying to solve.
 
 The `mix phx.gen.auth` task takes the following arguments: the module name of the context, the module name of the schema, and a plural version of the schema name used to generate database tables and route helpers.
 
@@ -258,7 +258,7 @@ $ mix phx.gen.auth Accounts User users
 * injecting lib/hello_web/templates/layout/app.html.eex
 ```
 
-When `mix phx.gen.auth` is done creating files, it helpfully tells us that we need to re-fetch our dependencies as well as run our ecto migrations.
+When `mix phx.gen.auth` is done creating files, it helpfully tells us that we need to re-fetch our dependencies as well as run our Ecto migrations.
 
 ```console
 Please re-fetch your dependencies with the following command:
@@ -270,11 +270,11 @@ Remember to update your repository by running migrations:
   $ mix ecto.migrate
 ```
 
-A more complete walk-through of how to get started with this generator is available in the [`mix phx.gen.auth` Guide](mix_phx_gen_auth.html).
+A more complete walk-through of how to get started with this generator is available in the [`mix phx.gen.auth` authentication guide](mix_phx_gen_auth.html).
 
 ### `mix phx.gen.channel`
 
-This task will generate a basic Phoenix channel as well a test case for it. It takes the module name for the channel as argument:
+This task will generate a basic Phoenix channel as well a test case for it. It takes the module name for the channel as the only one argument:
 
 ```console
 $ mix phx.gen.channel Room
@@ -292,7 +292,7 @@ Add the channel to your `lib/hello_web/channels/user_socket.ex` handler, for exa
 
 ### `mix phx.gen.presence`
 
-This task will generate a Presence tracker. The module name can be passed as an argument,
+This task will generate a presence tracker. The module name can be passed as an argument,
 `Presence` is used if no module name is passed.
 
 ```console
@@ -302,7 +302,7 @@ $ lib/hello_web/channels/presence.ex
 
 ### `mix phx.routes`
 
-This task has a single purpose, to show us all the routes defined for a given router. We saw it used extensively in the [Routing Guide](routing.html).
+This task has a single purpose, to show us all the routes defined for a given router. We saw it used extensively in the [routing guide](routing.html).
 
 If we don't specify a router for this task, it will default to the router Phoenix generated for us.
 
@@ -325,13 +325,13 @@ This is the task we use to get our application running. It takes no arguments at
 $ mix phx.server
 [info] Running TaskTesterWeb.Endpoint with Cowboy on port 4000 (http)
 ```
-It silently ignores our `DoesNotExist` argument.
+It will silently ignore our `DoesNotExist` argument:
 
 ```console
 $ mix phx.server DoesNotExist
 [info] Running TaskTesterWeb.Endpoint with Cowboy on port 4000 (http)
 ```
-If we would like to start our application and also have an `iex` session open to it, we can run the mix task within `iex` like this, `iex -S mix phx.server`.
+If we would like to start our application and also have an `IEx` session open to it, we can run the Mix task within `iex` like this, `iex -S mix phx.server`.
 
 ```console
 $ iex -S mix phx.server
@@ -346,11 +346,11 @@ iex(1)>
 
 This task does two things, it creates a digest for our static assets and then compresses them.
 
-"Digest" here refers to an MD5 digest of the contents of an asset which gets added to the filename of that asset. This creates a sort of "fingerprint" for it. If the digest doesn't change, browsers and CDNs will use a cached version. If it does change, they will re-fetch the new version.
+"Digest" here refers to an MD5 digest of the contents of an asset which gets added to the filename of that asset. This creates a sort of fingerprint for it. If the digest doesn't change, browsers and CDNs will use a cached version. If it does change, they will re-fetch the new version.
 
 Before we run this task let's inspect the contents of two directories in our hello application.
 
-First `priv/static` which should look similar to this:
+First `priv/static/` which should look similar to this:
 
 ```console
 ├── images
@@ -376,7 +376,7 @@ $ mix phx.digest
 Check your digested files at 'priv/static'.
 ```
 
-We can now do as the task suggests and inspect the contents of `priv/static` directory. We'll see that all files from `assets/` have been copied over to `priv/static` and also each file now has a couple of versions. Those versions are:
+We can now do as the task suggests and inspect the contents of `priv/static/` directory. We'll see that all files from `assets/` have been copied over to `priv/static/` and also each file now has a couple of versions. Those versions are:
 
 * the original file
 * a compressed file with gzip
@@ -392,13 +392,13 @@ config :phoenix, :gzippable_exts, ~w(.js .css)
 > Note: We can specify a different output folder where `mix phx.digest` will put processed files. The first argument is the path where the static files are located.
 
 ```console
-$ mix phx.digest priv/static -o www/public
-Check your digested files at 'www/public'.
+$ mix phx.digest priv/static/ -o www/public/
+Check your digested files at 'www/public/'
 ```
 
 ## Ecto tasks
 
-Newly generated Phoenix applications now include ecto and postgrex as dependencies by default (which is to say, unless we use `mix phx.new` with the `--no-ecto` flag). With those dependencies come mix tasks to take care of common ecto operations. Let's see which tasks we get out of the box.
+Newly generated Phoenix applications now include Ecto and Postgrex as dependencies by default (which is to say, unless we use `mix phx.new` with the `--no-ecto` flag). With those dependencies come Mix tasks to take care of common Ecto operations. Let's see which tasks we get out of the box.
 
 ```console
 $ mix help --search "ecto"
@@ -418,7 +418,7 @@ Note: We can run any of the tasks above with the `--no-start` flag to execute th
 
 ### `mix ecto.create`
 
-This task will create the database specified in our repo. By default it will look for the repo named after our application (the one generated with our app unless we opted out of ecto), but we can pass in another repo if we want.
+This task will create the database specified in our repo. By default it will look for the repo named after our application (the one generated with our app unless we opted out of Ecto), but we can pass in another repo if we want.
 
 Here's what it looks like in action.
 
@@ -487,7 +487,7 @@ The database for OurCustom.Repo has been created.
 
 ### `mix ecto.drop`
 
-This task will drop the database specified in our repo. By default it will look for the repo named after our application (the one generated with our app unless we opted out of ecto). It will not prompt us to check if we're sure we want to drop the db, so do exercise caution.
+This task will drop the database specified in our repo. By default it will look for the repo named after our application (the one generated with our app unless we opted out of Ecto). It will not prompt us to check if we're sure we want to drop the database, so do exercise caution.
 
 ```console
 $ mix ecto.drop
@@ -553,7 +553,7 @@ children = [
 
 ### `mix ecto.gen.migration`
 
-Migrations are a programmatic, repeatable way to affect changes to a database schema. Migrations are also just modules, and we can create them with the `ecto.gen.migration` task. Let's walk through the steps to create a migration for a new comments table.
+Migrations are a programmatic, repeatable way to affect changes to a database schema. Migrations are also just modules, and we can create them with the [`ecto.gen.migration`](`mix ecto.gen.migration`) task. Let's walk through the steps to create a migration for a new comments table.
 
 We simply need to invoke the task with a `snake_case` version of the module name that we want. Preferably, the name will describe what we want the migration to do.
 
@@ -601,7 +601,7 @@ $ mix ecto.gen.migration -r OurCustom.Repo add_users
 ```
 
 For more information on how to modify your database schema please refer to the
-Ecto's migration DSL [ecto migration docs](https://hexdocs.pm/ecto_sql/Ecto.Migration.html).
+[Ecto's migration DSL docs](https://hexdocs.pm/ecto_sql/Ecto.Migration.html).
 For example, to alter an existing schema see the documentation on Ecto’s
 [`alter/2`](https://hexdocs.pm/ecto_sql/Ecto.Migration.html#alter/2) function.
 
@@ -631,7 +631,7 @@ version        |     inserted_at
 (2 rows)
 ```
 
-When we roll back a migration, `ecto.rollback` will remove the record representing this migration from `schema_migrations`.
+When we roll back a migration, [`ecto.rollback`](#mix-ecto-rollback) will remove the record representing this migration from `schema_migrations`.
 
 By default, `ecto.migrate` will execute all pending migrations. We can exercise more control over which migrations we run by specifying some options when we run the task.
 
@@ -661,7 +661,7 @@ mix ecto.migrate --to 20150317170448
 
 ### `mix ecto.rollback`
 
-The `ecto.rollback` task will reverse the last migration we have run, undoing the schema changes. `ecto.migrate` and `ecto.rollback` are mirror images of each other.
+The [`ecto.rollback`](`mix ecto.rollback`) task will reverse the last migration we have run, undoing the schema changes. [`ecto.migrate`](#mix-ecto-migrate) and `ecto.rollback` are mirror images of each other.
 
 ```console
 $ mix ecto.rollback
@@ -674,12 +674,12 @@ $ mix ecto.rollback
 
 ## Creating our own Mix task
 
-As we've seen throughout this guide, both mix itself and the dependencies we bring in to our application provide a number of really useful tasks for free. Since neither of these could possibly anticipate all our individual application's needs, mix allows us to create our own custom tasks. That's exactly what we are going to do now.
+As we've seen throughout this guide, both Mix itself and the dependencies we bring in to our application provide a number of really useful tasks for free. Since neither of these could possibly anticipate all our individual application's needs, Mix allows us to create our own custom tasks. That's exactly what we are going to do now.
 
-The first thing we need to do is create a `mix/tasks` directory inside of `lib`. This is where any of our application specific mix tasks will go.
+The first thing we need to do is create a `mix/tasks/` directory inside of `lib/`. This is where any of our application specific Mix tasks will go.
 
 ```console
-$ mkdir -p lib/mix/tasks
+$ mkdir -p lib/mix/tasks/
 ```
 
 Inside that directory, let's create a new file, `hello.greeting.ex`, that looks like this.
@@ -691,7 +691,7 @@ defmodule Mix.Tasks.Hello.Greeting do
   @shortdoc "Sends a greeting to us from Hello Phoenix"
 
   @moduledoc """
-  This is where we would put any long form documentation or doctests.
+  This is where we would put any long form documentation and doctests.
   """
 
   def run(_args) do
@@ -702,18 +702,18 @@ defmodule Mix.Tasks.Hello.Greeting do
 end
 ```
 
-Let's take a quick look at the moving parts involved in a working mix task.
+Let's take a quick look at the moving parts involved in a working Mix task.
 
-The first thing we need to do is name our module. All tasks must be defined in `Mix.Tasks` namespace. We'd like to invoke this as `mix hello.greeting`, so we complete the module name with
+The first thing we need to do is name our module. All tasks must be defined in the `Mix.Tasks` namespace. We'd like to invoke this as `mix hello.greeting`, so we complete the module name with
 `Hello.Greeting`.
 
-The `use Mix.Task` line brings in functionality from Mix that makes this module behave as a mix task.
+The `use Mix.Task` line brings in functionality from Mix that makes this module [behave as a Mix task](`Mix.Task`).
 
 The `@shortdoc` module attribute holds a string which will describe our task when users invoke `mix help`.
 
 `@moduledoc` serves the same function that it does in any module. It's where we can put long-form documentation and doctests, if we have any.
 
-The `run/1` function is the critical heart of any Mix task. It's the function that does all the work when users invoke our task. In ours, all we do is send a greeting from our app, but we can implement our `run/1` function to do whatever we need it to. Note that `Mix.shell().info/1` is the preferred way to print text back out to the user.
+The [`run/1`](`c:Mix.Task.run/1`) function is the critical heart of any Mix task. It's the function that does all the work when users invoke our task. In ours, all we do is send a greeting from our app, but we can implement our `run/1` function to do whatever we need it to. Note that [`Mix.shell().info/1`](`Mix.shell/0`) is the preferred way to print text back out to the user.
 
 Of course, our task is just a module, so we can define other private functions as needed to support our `run/1` function.
 
@@ -743,13 +743,13 @@ Greetings from the Hello Phoenix Application!
 
 Indeed it does.
 
-If you want to make your new mix task to use your application's infrastructure, you need to make sure the application is started when mix task is being executed. This is particularly useful if you need to access your database from within the mix task. Thankfully, mix makes it really easy for us:
+If you want to make your new Mix task to use your application's infrastructure, you need to make sure the application is started when Mix task is being executed. This is particularly useful if you need to access your database from within the Mix task. Thankfully, Mix makes it really easy for us:
 
 ```elixir
-  . . .
   def run(_args) do
     Mix.Task.run("app.start")
     Mix.shell().info("Now I have access to Repo and other goodies!")
+    Mix.shell().info("Greetings from the Hello Phoenix Application!")    
   end
-  . . .
 ```
+
diff --git a/guides/realtime/channels.md b/guides/realtime/channels.md
index b2b2a790a..5424ec504 100644
--- a/guides/realtime/channels.md
+++ b/guides/realtime/channels.md
@@ -54,7 +54,7 @@ Let's take a look at them.
 
 ### Overview
 
-To start communicating, a client connects to a node (a Phoenix server) using a transport (eg, Websockets or long polling) and joins one or more channels using that single network connection.
+To start communicating, a client connects to a node (a Phoenix server) using a transport (e.g., Websockets or long polling) and joins one or more channels using that single network connection.
 One channel server process is created per client, per topic.
 The appropriate socket handler initializes a `%Phoenix.Socket` for the channel server (possibly after authenticating the client).
 The channel server then holds onto the `%Phoenix.Socket{}` and can maintain any state it needs within its `socket.assigns`.
@@ -351,7 +351,7 @@ end
 
 ### Intercepting Outgoing Events
 
-We won't implement this for our application, but imagine our chat app allowed users to ignore messages about new users joining a room. We could implement that behavior like this where we explicitly tell Phoenix which outgoing event we want to intercept and then define a `handle_out/3` callback for those events. (Of course, this assumes that we have a `Accounts` context with an `ignoring_user?/2` function, and that we pass a user in via the `assigns` map). It is important to note that the `handle_out/3` callback will be called for every recipient of a message, so more expensive operations like hitting the database should be considered carefully before being included in `handle_out/3`.
+We won't implement this for our application, but imagine our chat app allowed users to ignore messages about new users joining a room. We could implement that behavior like this where we explicitly tell Phoenix which outgoing event we want to intercept and then define a `handle_out/3` callback for those events. (Of course, this assumes that we have an `Accounts` context with an `ignoring_user?/2` function, and that we pass a user in via the `assigns` map). It is important to note that the `handle_out/3` callback will be called for every recipient of a message, so more expensive operations like hitting the database should be considered carefully before being included in `handle_out/3`.
 
 ```elixir
 intercept ["user_joined"]
@@ -456,7 +456,7 @@ Servers restart, networks split, and clients lose connectivity. In order to desi
 
 ### Handling Reconnection
 
-Clients subscribe to topics, and Phoenix stores those subscriptions in an in-memory ETS table. If a channel crashes, the clients will need to reconnect to the topics they had previously subscribed to. Fortunately, the Phoenix JavaScript client knows how to do this. The server will notify all the clients of the crash. This will trigger each client's `Channel.onError` callback. The clients will attempt to reconnect to the server using an exponential back off strategy. Once they reconnect, they'll attempt to rejoin the topics they had previously subscribed to. If they are successful, they'll start receiving messages from those topics as before.
+Clients subscribe to topics, and Phoenix stores those subscriptions in an in-memory ETS table. If a channel crashes, the clients will need to reconnect to the topics they had previously subscribed to. Fortunately, the Phoenix JavaScript client knows how to do this. The server will notify all the clients of the crash. This will trigger each client's `Channel.onError` callback. The clients will attempt to reconnect to the server using an exponential backoff strategy. Once they reconnect, they'll attempt to rejoin the topics they had previously subscribed to. If they are successful, they'll start receiving messages from those topics as before.
 
 ### Resending Client Messages
 
diff --git a/guides/routing.md b/guides/routing.md
index dc44ac545..e29b46a31 100644
--- a/guides/routing.md
+++ b/guides/routing.md
@@ -160,7 +160,7 @@ This is significant because we can use the `page_path` function in a template to
 <%= link "Welcome Page!", to: Routes.page_path(@conn, :index) %>
 ```
 
-The reason we can use `Routes.page_path` instead of the full `HelloWeb.Router.Helpers.page_path` name is because `HelloWeb.Router.Helpers` is aliased as `Routes` by default in the `view/0` block defined inside `lib/hello_web.ex`. This definition is made available to our templates through `use HelloWeb, :view`.
+The reason we can use `Routes.page_path` instead of the full `HelloWeb.Router.Helpers.page_path` name is because `HelloWeb.Router.Helpers` is aliased as `Routes` by default in the `view_helpers/0` block defined inside `lib/hello_web.ex`. This definition is made available to our templates through `use HelloWeb, :view`.
 
 We can, of course, use `HelloWeb.Router.Helpers.page_path(@conn, :index)` instead, but the convention is to use the aliased version for conciseness. Note that the alias is only set automatically for use in views, controllers and templates - outside these you need either the full name, or to alias it yourself inside the module definition with `alias HelloWeb.Router.Helpers, as: Routes`.
 
diff --git a/guides/views.md b/guides/views.md
index be418666a..b720964d7 100644
--- a/guides/views.md
+++ b/guides/views.md
@@ -268,7 +268,6 @@ end
 ```
 
 The name used in assigns is determined from the view. For example `PageView` will use `%{page: page}` and `AuthorView` will use `%{author: author}`. This can be overridden with the `as` option. Let's assume that the author view uses `%{writer: writer}` instead of `%{author: author}`:
->>>>>>> ff14fd75 (Fix grammar. Remove article "the" before controllers and views.)
 
 ```elixir
 def render("page_with_authors.json", %{page: page}) do
@@ -283,8 +282,8 @@ Phoenix has a view called `ErrorView` which lives in `lib/hello_web/views/error_
 
 
 [welcome page]: http://localhost:4000
-[`render/2`]: Phoenix.View.render/3
-[`render/3`]: Phoenix.View.render/3
-[`render_many/3`]: Phoenix.View.render_many/3
-[`render_one/3`]: Phoenix.View.render_one/3
-[`render_to_string/3`]: Phoenix.View.render_to_string/3
+[`render/2`]: `Phoenix.View.render/3`
+[`render/3`]: `Phoenix.View.render/3`
+[`render_many/3`]: `Phoenix.View.render_many/3`
+[`render_one/3`]: `Phoenix.View.render_one/3`
+[`render_to_string/3`]: `Phoenix.View.render_to_string/3`
diff --git a/installer/lib/mix/tasks/phx.new.ex b/installer/lib/mix/tasks/phx.new.ex
index 561fcea2b..bdd04df91 100644
--- a/installer/lib/mix/tasks/phx.new.ex
+++ b/installer/lib/mix/tasks/phx.new.ex
@@ -51,6 +51,8 @@ defmodule Mix.Tasks.Phx.New do
 
     * `--verbose` - use verbose output
 
+    * `-v`, `--version` - prints the Phoenix installer version
+
   When passing the `--no-ecto` flag, Phoenix generators such as
   `phx.gen.html`, `phx.gen.json`, `phx.gen.live`, and `phx.gen.context`
   may no longer work as expected as they generate context files that rely
@@ -93,10 +95,6 @@ defmodule Mix.Tasks.Phx.New do
 
   You can read more about umbrella projects using the
   official [Elixir guide](http://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#umbrella-projects)
-
-  To print the Phoenix installer version, pass `-v` or `--version`, for example:
-
-      mix phx.new -v
   """
   use Mix.Task
   alias Phx.New.{Generator, Project, Single, Umbrella, Web, Ecto}
@@ -108,11 +106,12 @@ defmodule Mix.Tasks.Phx.New do
              app: :string, module: :string, web_module: :string,
              database: :string, binary_id: :boolean, html: :boolean,
              gettext: :boolean, umbrella: :boolean, verbose: :boolean,
-             live: :boolean, dashboard: :boolean, install: :boolean]
+             live: :boolean, dashboard: :boolean, install: :boolean,
+             prefix: :string]
 
   @impl true
   def run([version]) when version in ~w(-v --version) do
-    Mix.shell().info("Phoenix v#{@version}")
+    Mix.shell().info("Phoenix installer v#{@version}")
   end
 
   def run(argv) do
diff --git a/installer/lib/phx_new/generator.ex b/installer/lib/phx_new/generator.ex
index 420d0a822..49a2fb6d0 100644
--- a/installer/lib/phx_new/generator.ex
+++ b/installer/lib/phx_new/generator.ex
@@ -264,7 +264,8 @@ defmodule Phx.New.Generator do
     config :#{binding[:app_name]}, #{binding[:app_module]}.Repo,
       # ssl: true,
       url: database_url,
-      pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
+      pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
+      socket_options: [:inet6]
     """)
   end
 
diff --git a/installer/mix.exs b/installer/mix.exs
index ce748dcb4..53200c7b9 100644
--- a/installer/mix.exs
+++ b/installer/mix.exs
@@ -7,8 +7,7 @@ defmodule Phx.New.MixProject do
   use Mix.Project
 
   @version "1.6.0-dev"
-  @github_path "phoenixframework/phoenix"
-  @url "https://github.com/#{@github_path}"
+  @scm_url "https://github.com/phoenixframework/phoenix"
 
   def project do
     [
@@ -25,10 +24,11 @@ defmodule Phx.New.MixProject do
           "Jason Stiebs"
         ],
         licenses: ["MIT"],
-        links: %{github: @url},
+        links: %{"GitHub" => @scm_url},
         files: ~w(lib templates mix.exs README.md)
       ],
-      source_url: @url,
+      preferred_cli_env: [docs: :docs],
+      source_url: @scm_url,
       docs: docs(),
       homepage_url: "https://www.phoenixframework.org",
       description: """
@@ -48,14 +48,13 @@ defmodule Phx.New.MixProject do
 
   def deps do
     [
-      {:ex_doc, "~> 0.23", only: :docs}
+      {:ex_doc, "~> 0.24", only: :docs}
     ]
   end
 
   defp docs do
     [
-      source_url_pattern:
-        "https://github.com/#{@github_path}/blob/v#{@version}/installer/%{path}#L%{line}"
+      source_url_pattern: "#{@scm_url}/blob/v#{@version}/installer/%{path}#L%{line}"
     ]
   end
 end
diff --git a/installer/mix.lock b/installer/mix.lock
index e2b0b780c..843b4accd 100644
--- a/installer/mix.lock
+++ b/installer/mix.lock
@@ -1,8 +1,9 @@
 %{
   "earmark": {:hex, :earmark, "1.4.10", "bddce5e8ea37712a5bfb01541be8ba57d3b171d3fa4f80a0be9bcf1db417bcaf", [:mix], [{:earmark_parser, ">= 1.4.10", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "12dbfa80810478e521d3ffb941ad9fbfcbbd7debe94e1341b4c4a1b2411c1c27"},
-  "earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"},
-  "ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"},
+  "earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
+  "ex_doc": {:hex, :ex_doc, "0.24.1", "15673de99154f93ca7f05900e4e4155ced1ee0cd34e0caeee567900a616871a4", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "07972f17bdf7dc7b5bd76ec97b556b26178ed3f056e7ec9288eb7cea7f91cce2"},
   "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
-  "makeup_elixir": {:hex, :makeup_elixir, "0.15.0", "98312c9f0d3730fde4049985a1105da5155bfe5c11e47bdc7406d88e01e4219b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "75ffa34ab1056b7e24844c90bfc62aaf6f3a37a15faa76b07bc5eba27e4a8b4a"},
+  "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
+  "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
   "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
 }
diff --git a/installer/templates/phx_single/config/config.exs b/installer/templates/phx_single/config/config.exs
index 44ac95008..5ffdbae19 100644
--- a/installer/templates/phx_single/config/config.exs
+++ b/installer/templates/phx_single/config/config.exs
@@ -1,5 +1,5 @@
 # This file is responsible for configuring your application
-# and its dependencies with the aid of the Mix.Config module.
+# and its dependencies with the aid of the Config module.
 #
 # This configuration file is loaded before any dependency and
 # is restricted to this project.
diff --git a/installer/templates/phx_umbrella/config/config.exs b/installer/templates/phx_umbrella/config/config.exs
index 7163afb34..4b232332d 100644
--- a/installer/templates/phx_umbrella/config/config.exs
+++ b/installer/templates/phx_umbrella/config/config.exs
@@ -1,6 +1,6 @@
 # This file is responsible for configuring your umbrella
 # and **all applications** and their dependencies with the
-# help of Mix.Config.
+# help of the Config module.
 #
 # Note that all applications in your umbrella share the
 # same configuration and dependencies, which is why they
diff --git a/lib/mix/phoenix/schema.ex b/lib/mix/phoenix/schema.ex
index cadc130e6..775930da6 100644
--- a/lib/mix/phoenix/schema.ex
+++ b/lib/mix/phoenix/schema.ex
@@ -35,7 +35,8 @@ defmodule Mix.Phoenix.Schema do
             route_helper: nil,
             migration_module: nil,
             fixture_unique_functions: %{},
-            fixture_params: %{}
+            fixture_params: %{},
+            prefix: nil
 
   @valid_types [
     :integer,
@@ -136,7 +137,9 @@ defmodule Mix.Phoenix.Schema do
       generate?: generate?,
       migration_module: migration_module(),
       fixture_unique_functions: fixture_unique_functions,
-      fixture_params: fixture_params(attrs, fixture_unique_functions)}
+      fixture_params: fixture_params(attrs, fixture_unique_functions),
+      prefix: opts[:prefix]
+    }
   end
 
   @doc """
diff --git a/lib/mix/tasks/compile.phoenix.ex b/lib/mix/tasks/compile.phoenix.ex
index 010afcde4..a97a81c71 100644
--- a/lib/mix/tasks/compile.phoenix.ex
+++ b/lib/mix/tasks/compile.phoenix.ex
@@ -4,6 +4,11 @@ defmodule Mix.Tasks.Compile.Phoenix do
 
   @moduledoc """
   Compiles Phoenix source files that support code reloading.
+  
+  If you are using Elixir v1.11+ or later, there is no longer
+  a need to use this module as this functionality is now provided
+  by Elixir. Just remember to update `__phoenix_recompile__?` to
+  `__mix_recompile__?` in any module that may define it.
   """
 
   # TODO: Deprecate this module once we require Elixir v1.11+
diff --git a/lib/mix/tasks/phx.ex b/lib/mix/tasks/phx.ex
index d460df13c..b76275317 100644
--- a/lib/mix/tasks/phx.ex
+++ b/lib/mix/tasks/phx.ex
@@ -8,9 +8,20 @@ defmodule Mix.Tasks.Phx do
 
       mix phx
 
+  To print the Phoenix version, pass `-v` or `--version`, for example:
+
+      mix phx --version
+
   """
 
+  @version Mix.Project.config()[:version]
+
+  @impl true
   @doc false
+  def run([version]) when version in ~w(-v --version) do
+    Mix.shell().info("Phoenix v#{@version}")
+  end
+
   def run(args) do
     case args do
       [] -> general()
@@ -21,9 +32,9 @@ defmodule Mix.Tasks.Phx do
   defp general() do
     Application.ensure_all_started(:phoenix)
     Mix.shell().info "Phoenix v#{Application.spec(:phoenix, :vsn)}"
-    Mix.shell().info "Productive. Reliable. Fast."
-    Mix.shell().info "A productive web framework that does not compromise speed or maintainability."
-    Mix.shell().info "\nAvailable tasks:\n"
+    Mix.shell().info "Peace of mind from prototype to production"
+    Mix.shell().info "\n## Options\n"
+    Mix.shell().info "-v, --version        # Prints Phoenix version\n"
     Mix.Tasks.Help.run(["--search", "phx."])
   end
 end
diff --git a/lib/mix/tasks/phx.gen.auth.ex b/lib/mix/tasks/phx.gen.auth.ex
index 52c27a510..c9422ba25 100644
--- a/lib/mix/tasks/phx.gen.auth.ex
+++ b/lib/mix/tasks/phx.gen.auth.ex
@@ -82,7 +82,8 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
   alias Mix.Tasks.Phx.Gen.Auth.{HashingLibrary, Injector, Migration}
 
   @switches [web: :string, binary_id: :boolean, hashing_lib: :string,
-             table: :string, merge_with_existing_context: :boolean]
+             table: :string, merge_with_existing_context: :boolean,
+             prefix: :string]
 
   @doc false
   def run(args, test_opts \\ []) do
@@ -276,6 +277,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
 
     paths
     |> Mix.Phoenix.eval_from("priv/templates/phx.gen.auth/context_fixtures_functions.ex", binding)
+    |> prepend_newline()
     |> inject_before_final_end(test_fixtures_file)
   end
 
diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex
index 839c51dba..2193d6561 100644
--- a/lib/mix/tasks/phx.gen.context.ex
+++ b/lib/mix/tasks/phx.gen.context.ex
@@ -80,7 +80,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
 
   @switches [binary_id: :boolean, table: :string, web: :string,
              schema: :boolean, context: :boolean, context_app: :string,
-             merge_with_existing_context: :boolean]
+             merge_with_existing_context: :boolean, prefix: :string]
 
   @default_opts [schema: true, context: true]
 
diff --git a/lib/mix/tasks/phx.gen.schema.ex b/lib/mix/tasks/phx.gen.schema.ex
index f3c4ec536..627f7173e 100644
--- a/lib/mix/tasks/phx.gen.schema.ex
+++ b/lib/mix/tasks/phx.gen.schema.ex
@@ -103,7 +103,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
   alias Mix.Phoenix.Schema
 
   @switches [migration: :boolean, binary_id: :boolean, table: :string,
-             web: :string, context_app: :string]
+             web: :string, context_app: :string, prefix: :string]
 
   @doc false
   def run(args) do
diff --git a/lib/phoenix/code_reloader.ex b/lib/phoenix/code_reloader.ex
index b1b33211d..cfbb56264 100644
--- a/lib/phoenix/code_reloader.ex
+++ b/lib/phoenix/code_reloader.ex
@@ -2,18 +2,6 @@ defmodule Phoenix.CodeReloader do
   @moduledoc """
   A plug and module to handle automatic code reloading.
 
-  For each request, Phoenix goes through all modules and checks if any of
-  them implement a `__phoenix_recompile__?/0` function. If they do and
-  it returns true, the module source file is touched, forcing it to be
-  recompiled. For this functionality to work, Phoenix requires you to add
-  the `:phoenix` compiler to your list of compilers:
-
-      compilers: [:phoenix] ++ Mix.compilers()
-
-  This is useful, for example, to recompile modules that depend on external
-  systems, such as directories, databases, etc. Note if you simply depend on
-  external files, `@external_resource` annotation should be used.
-
   To avoid race conditions, all code reloads are funneled through a
   sequential call operation.
   """
diff --git a/lib/phoenix/presence.ex b/lib/phoenix/presence.ex
index f9d5a759d..755a58b83 100644
--- a/lib/phoenix/presence.ex
+++ b/lib/phoenix/presence.ex
@@ -63,10 +63,10 @@ defmodule Phoenix.Presence do
         end
       end
 
-  In the example above, the current presence information for
-  the socket's topic is pushed to the client as a `"presence_state"` event.
-  Next, `Presence.track` is used to register this channel's process as a
+  In the example above, `Presence.track` is used to register this channel's process as a
   presence for the socket's user ID, with a map of metadata.
+  Next, the current presence information for
+  the socket's topic is pushed to the client as a `"presence_state"` event.
 
   Finally, a diff of presence join and leave events will be sent to the
   client as they happen in real-time with the "presence_diff" event.
diff --git a/lib/phoenix/router/helpers.ex b/lib/phoenix/router/helpers.ex
index 1fdd30d02..fa3041e01 100644
--- a/lib/phoenix/router/helpers.ex
+++ b/lib/phoenix/router/helpers.ex
@@ -345,7 +345,7 @@ defmodule Phoenix.Router.Helpers do
   """
   def raise_route_error(mod, fun, arity, action, routes, params) do
     cond do
-      not Keyword.has_key?(routes, action) ->
+      is_atom(action) and not Keyword.has_key?(routes, action) ->
         "no action #{inspect action} for #{inspect mod}.#{fun}/#{arity}"
         |> invalid_route_error(fun, routes)
 
diff --git a/mix.exs b/mix.exs
index d7ba09851..30a25e33c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -2,10 +2,13 @@ defmodule Phoenix.MixProject do
   use Mix.Project
 
   @version "1.6.0-dev"
+  @scm_url "https://github.com/phoenixframework/phoenix"
 
   # If the elixir requirement is updated, we need to make the installer
   # use at least the minimum requirement used here. Although often the
   # installer is ahead of Phoenix itself.
+  #
+  # We also need to update guides/introduction/installation.md
   @elixir_requirement "~> 1.9"
 
   def project do
@@ -31,7 +34,7 @@ defmodule Phoenix.MixProject do
       name: "Phoenix",
       docs: docs(),
       aliases: aliases(),
-      source_url: "https://github.com/phoenixframework/phoenix",
+      source_url: @scm_url,
       homepage_url: "https://www.phoenixframework.org",
       description: """
       Productive. Reliable. Fast. A productive web framework that
@@ -52,7 +55,7 @@ defmodule Phoenix.MixProject do
         stacktrace_depth: nil,
         filter_parameters: ["password"],
         serve_endpoints: false,
-        gzippable_exts: ~w(.js .css .txt .text .html .json .svg .eot .ttf),
+        gzippable_exts: ~w(.js .map .css .txt .text .html .json .svg .eot .ttf),
         static_compressors: [Phoenix.Digester.Gzip]
       ]
     ]
@@ -72,8 +75,9 @@ defmodule Phoenix.MixProject do
       {:phoenix_html, "~> 2.14.2 or ~> 3.0", optional: true},
 
       # Docs dependencies (some for cross references)
-      {:ex_doc, "~> 0.22", only: :docs},
+      {:ex_doc, "~> 0.24", only: :docs},
       {:ecto, ">= 3.0.0", only: :docs},
+      {:ecto_sql, "~> 3.5", only: :docs},
       {:gettext, "~> 0.15.0", only: :docs},
       {:telemetry_poller, "~> 0.4", only: :docs},
       {:telemetry_metrics, "~> 0.4", only: :docs},
@@ -88,7 +92,7 @@ defmodule Phoenix.MixProject do
     [
       maintainers: ["Chris McCord", "José Valim", "Gary Rennie", "Jason Stiebs"],
       licenses: ["MIT"],
-      links: %{"GitHub" => "https://github.com/phoenixframework/phoenix"},
+      links: %{"GitHub" => @scm_url},
       files:
         ~w(assets/js lib priv CHANGELOG.md LICENSE.md mix.exs package.json README.md .formatter.exs)
     ]
@@ -165,7 +169,6 @@ defmodule Phoenix.MixProject do
     # Phoenix.Presence
     # Phoenix.Router
     # Phoenix.Token
-    # Phoenix.View
 
     [
       Testing: [
@@ -183,12 +186,6 @@ defmodule Phoenix.MixProject do
         Phoenix.Socket.Reply,
         Phoenix.Socket.Serializer,
         Phoenix.Socket.Transport
-      ],
-      Templating: [
-        Phoenix.Template,
-        Phoenix.Template.EExEngine,
-        Phoenix.Template.Engine,
-        Phoenix.Template.ExsEngine
       ]
     ]
   end
diff --git a/mix.lock b/mix.lock
index d333b9264..6d102e9cb 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,14 +1,18 @@
 %{
+  "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
   "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"},
   "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
+  "db_connection": {:hex, :db_connection, "2.3.1", "4c9f3ed1ef37471cbdd2762d6655be11e38193904d9c5c1c9389f1b891a3088e", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "abaab61780dde30301d840417890bd9f74131041afd02174cf4e10635b3a63f5"},
   "decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
-  "earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"},
+  "earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
   "ecto": {:hex, :ecto, "3.5.5", "48219a991bb86daba6e38a1e64f8cea540cded58950ff38fbc8163e062281a07", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98dd0e5e1de7f45beca6130d13116eae675db59adfa055fb79612406acf6f6f1"},
-  "ex_doc": {:hex, :ex_doc, "0.23.0", "a069bc9b0bf8efe323ecde8c0d62afc13d308b1fa3d228b65bca5cf8703a529d", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "f5e2c4702468b2fd11b10d39416ddadd2fcdd173ba2a0285ebd92c39827a5a16"},
+  "ecto_sql": {:hex, :ecto_sql, "3.5.4", "a9e292c40bd79fff88885f95f1ecd7b2516e09aa99c7dd0201aa84c54d2358e4", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1fff1a28a898d7bbef263f1f3ea425b04ba9f33816d843238c84eff883347343"},
+  "ex_doc": {:hex, :ex_doc, "0.24.1", "15673de99154f93ca7f05900e4e4155ced1ee0cd34e0caeee567900a616871a4", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "07972f17bdf7dc7b5bd76ec97b556b26178ed3f056e7ec9288eb7cea7f91cce2"},
   "gettext": {:hex, :gettext, "0.15.0", "40a2b8ce33a80ced7727e36768499fc9286881c43ebafccae6bab731e2b2b8ce", [:mix], [], "hexpm", "d17ac3aa40835f7feb92913fcdf655edea59938fa8b25f5ce5d423e76a695c3b"},
   "jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b96c400e04b7b765c0854c05a4966323e90c0d11fee0483b1567cda079abb205"},
   "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
-  "makeup_elixir": {:hex, :makeup_elixir, "0.15.0", "98312c9f0d3730fde4049985a1105da5155bfe5c11e47bdc7406d88e01e4219b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "75ffa34ab1056b7e24844c90bfc62aaf6f3a37a15faa76b07bc5eba27e4a8b4a"},
+  "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
+  "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
   "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"},
   "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
   "phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
diff --git a/priv/templates/phx.gen.auth/confirmation_controller.ex b/priv/templates/phx.gen.auth/confirmation_controller.ex
index ea9728ca2..e7d00ff3e 100644
--- a/priv/templates/phx.gen.auth/confirmation_controller.ex
+++ b/priv/templates/phx.gen.auth/confirmation_controller.ex
@@ -15,7 +15,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       )
     end
 
-    # Regardless of the outcome, show an impartial success/error message.
+    # In order to prevent user enumeration attacks, regardless of the outcome, show an impartial success/error message.
     conn
     |> put_flash(
       :info,
diff --git a/priv/templates/phx.gen.auth/context_fixtures_functions.ex b/priv/templates/phx.gen.auth/context_fixtures_functions.ex
index ec909a30d..fd53675ba 100644
--- a/priv/templates/phx.gen.auth/context_fixtures_functions.ex
+++ b/priv/templates/phx.gen.auth/context_fixtures_functions.ex
@@ -1,14 +1,17 @@
-
   def unique_<%= schema.singular %>_email, do: "<%= schema.singular %>#{System.unique_integer()}@example.com"
   def valid_<%= schema.singular %>_password, do: "hello world!"
 
+  def valid_<%= schema.singular %>_attributes(attrs \\ %{}) do
+    Enum.into(attrs, %{
+      email: unique_<%= schema.singular %>_email(),
+      password: valid_<%= schema.singular %>_password()
+    })
+  end
+
   def <%= schema.singular %>_fixture(attrs \\ %{}) do
     {:ok, <%= schema.singular %>} =
       attrs
-      |> Enum.into(%{
-        email: unique_<%= schema.singular %>_email(),
-        password: valid_<%= schema.singular %>_password()
-      })
+      |> valid_<%= schema.singular %>_attributes()
       |> <%= inspect context.module %>.register_<%= schema.singular %>()
 
     <%= schema.singular %>
diff --git a/priv/templates/phx.gen.auth/reset_password_controller.ex b/priv/templates/phx.gen.auth/reset_password_controller.ex
index 74c21497e..9c8fb502d 100644
--- a/priv/templates/phx.gen.auth/reset_password_controller.ex
+++ b/priv/templates/phx.gen.auth/reset_password_controller.ex
@@ -17,7 +17,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       )
     end
 
-    # Regardless of the outcome, show an impartial success/error message.
+    # In order to prevent user enumeration attacks, regardless of the outcome, show an impartial success/error message.
     conn
     |> put_flash(
       :info,
diff --git a/priv/templates/phx.gen.auth/session_controller.ex b/priv/templates/phx.gen.auth/session_controller.ex
index 84396b103..09264334d 100644
--- a/priv/templates/phx.gen.auth/session_controller.ex
+++ b/priv/templates/phx.gen.auth/session_controller.ex
@@ -14,6 +14,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
     if <%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>_by_email_and_password(email, password) do
       <%= inspect schema.alias %>Auth.log_in_<%= schema.singular %>(conn, <%= schema.singular %>, <%= schema.singular %>_params)
     else
+      # In order to prevent user enumeration attacks, don't disclose whether the email is registered.
       render(conn, "new.html", error_message: "Invalid email or password")
     end
   end
diff --git a/priv/templates/phx.gen.schema/migration.exs b/priv/templates/phx.gen.schema/migration.exs
index 8cdb2630a..34a91963f 100644
--- a/priv/templates/phx.gen.schema/migration.exs
+++ b/priv/templates/phx.gen.schema/migration.exs
@@ -2,7 +2,7 @@ defmodule <%= inspect schema.repo %>.Migrations.Create<%= Macro.camelize(schema.
   use <%= inspect schema.migration_module %>
 
   def change do
-    create table(:<%= schema.table %><%= if schema.binary_id do %>, primary_key: false<% end %>) do
+    create table(:<%= schema.table %><%= if schema.binary_id do %>, primary_key: false<% end %><%= if schema.prefix do %>, prefix: :<%= schema.prefix %><% end %>) do
 <%= if schema.binary_id do %>      add :id, :binary_id, primary_key: true
 <% end %><%= for {k, v} <- schema.attrs do %>      add <%= inspect k %>, <%= inspect Mix.Phoenix.Schema.type_for_migration(v) %><%= schema.migration_defaults[k] %>
 <% end %><%= for {_, i, _, s} <- schema.assocs do %>      add <%= inspect(i) %>, references(<%= inspect(s) %>, on_delete: :nothing<%= if schema.binary_id do %>, type: :binary_id<% end %>)
diff --git a/priv/templates/phx.gen.schema/schema.ex b/priv/templates/phx.gen.schema/schema.ex
index ea7e44f03..63a19d420 100644
--- a/priv/templates/phx.gen.schema/schema.ex
+++ b/priv/templates/phx.gen.schema/schema.ex
@@ -1,7 +1,8 @@
 defmodule <%= inspect schema.module %> do
   use Ecto.Schema
   import Ecto.Changeset
-<%= if schema.binary_id do %>
+<%= if schema.prefix do %>
+  @schema_prefix :<%= schema.prefix %><% end %><%= if schema.binary_id do %>
   @primary_key {:id, :binary_id, autogenerate: true}
   @foreign_key_type :binary_id<% end %>
   schema <%= inspect schema.table %> do


Test patch:
diff --git a/installer/test/phx_new_test.exs b/installer/test/phx_new_test.exs
index e3d66dd24..0f086746c 100644
--- a/installer/test/phx_new_test.exs
+++ b/installer/test/phx_new_test.exs
@@ -23,7 +23,7 @@ defmodule Mix.Tasks.Phx.NewTest do
 
   test "returns the version" do
     Mix.Tasks.Phx.New.run(["-v"])
-    assert_received {:mix_shell, :info, ["Phoenix v" <> _]}
+    assert_received {:mix_shell, :info, ["Phoenix installer v" <> _]}
   end
 
   test "new with defaults" do
diff --git a/priv/templates/phx.gen.auth/registration_controller_test.exs b/priv/templates/phx.gen.auth/registration_controller_test.exs
index 4daf6ec12..02ac94dd4 100644
--- a/priv/templates/phx.gen.auth/registration_controller_test.exs
+++ b/priv/templates/phx.gen.auth/registration_controller_test.exs
@@ -25,7 +25,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       conn =
         post(conn, Routes.<%= schema.route_helper %>_registration_path(conn, :create), %{
-          "<%= schema.singular %>" => %{"email" => email, "password" => valid_<%= schema.singular %>_password()}
+          "<%= schema.singular %>" => valid_<%= schema.singular %>_attributes(email: email)
         })
 
       assert get_session(conn, :<%= schema.singular %>_token)
diff --git a/priv/templates/phx.gen.auth/test_cases.exs b/priv/templates/phx.gen.auth/test_cases.exs
index 8a0fa67a4..a29397e13 100644
--- a/priv/templates/phx.gen.auth/test_cases.exs
+++ b/priv/templates/phx.gen.auth/test_cases.exs
@@ -81,7 +81,7 @@
 
     test "registers <%= schema.plural %> with a hashed password" do
       email = unique_<%= schema.singular %>_email()
-      {:ok, <%= schema.singular %>} = <%= inspect context.alias %>.register_<%= schema.singular %>(%{email: email, password: valid_<%= schema.singular %>_password()})
+      {:ok, <%= schema.singular %>} = <%= inspect context.alias %>.register_<%= schema.singular %>(valid_<%= schema.singular %>_attributes(email: email))
       assert <%= schema.singular %>.email == email
       assert is_binary(<%= schema.singular %>.hashed_password)
       assert is_nil(<%= schema.singular %>.confirmed_at)
@@ -100,7 +100,10 @@
       password = valid_<%= schema.singular %>_password()
 
       changeset =
-        <%= inspect context.alias %>.change_<%= schema.singular %>_registration(%<%= inspect schema.alias %>{}, %{"email" => email, "password" => password})
+        <%= inspect context.alias %>.change_<%= schema.singular %>_registration(
+          %<%= inspect schema.alias %>{},
+          valid_<%= schema.singular %>_attributes(email: email, password: password)
+        )
 
       assert changeset.valid?
       assert get_change(changeset, :email) == email
diff --git a/test/mix/tasks/phx.gen.auth_test.exs b/test/mix/tasks/phx.gen.auth_test.exs
index 1eac38a1d..7f6d173d7 100644
--- a/test/mix/tasks/phx.gen.auth_test.exs
+++ b/test/mix/tasks/phx.gen.auth_test.exs
@@ -217,7 +217,10 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
       assert_file "lib/my_app/accounts/user_token.ex"
       assert_file "lib/my_app/accounts/user_notifier.ex"
       assert_file "test/my_app/accounts_test.exs"
-      assert_file "test/support/fixtures/accounts_fixtures.ex"
+
+      assert_file "test/support/fixtures/accounts_fixtures.ex", fn file ->
+        assert file =~ ~s|def valid_user_attributes(attrs \\\\ %{}) do|
+      end
 
       assert_file "lib/my_app_web/controllers/warehouse/user_auth.ex", fn file ->
         assert file =~ "defmodule MyAppWeb.Warehouse.UserAuth do"
diff --git a/test/mix/tasks/phx.gen.schema_test.exs b/test/mix/tasks/phx.gen.schema_test.exs
index 35598072d..caab17f49 100644
--- a/test/mix/tasks/phx.gen.schema_test.exs
+++ b/test/mix/tasks/phx.gen.schema_test.exs
@@ -258,6 +258,21 @@ defmodule Mix.Tasks.Phx.Gen.SchemaTest do
     end
   end
 
+  test "generates schema and migration with prefix", config do
+    in_tmp_project config.test, fn ->
+      Gen.Schema.run(~w(Blog.Post posts title --prefix cms))
+
+      assert_file "lib/phoenix/blog/post.ex", fn file ->
+        assert file =~ "@schema_prefix :cms"
+      end
+
+      assert [migration] = Path.wildcard("priv/repo/migrations/*_create_posts.exs")
+      assert_file migration, fn file ->
+        assert file =~ "create table(:posts, prefix: :cms) do"
+      end
+    end
+  end
+
   test "skips migration with --no-migration option", config do
     in_tmp_project config.test, fn ->
       Gen.Schema.run(~w(Blog.Post posts --no-migration))
diff --git a/test/phoenix/digester_test.exs b/test/phoenix/digester_test.exs
index 12cccaf8b..78594f2e6 100644
--- a/test/phoenix/digester_test.exs
+++ b/test/phoenix/digester_test.exs
@@ -24,6 +24,8 @@ defmodule Phoenix.DigesterTest do
       refute "phoenix.png.gz" in output_files
       assert "app.js" in output_files
       assert "app.js.gz" in output_files
+      assert "app.js.map" in output_files
+      assert "app.js.map.gz" in output_files
       assert "css/app.css" in output_files
       assert "css/app.css.gz" in output_files
       assert "manifest.json" in output_files
diff --git a/test/phoenix/integration/endpoint_test.exs b/test/phoenix/integration/endpoint_test.exs
index 832c4ec58..2fe130960 100644
--- a/test/phoenix/integration/endpoint_test.exs
+++ b/test/phoenix/integration/endpoint_test.exs
@@ -18,24 +18,15 @@ defmodule Phoenix.Integration.EndpointTest do
   @prod_inet6 prod_inet6
 
   Application.put_env(:endpoint_int, ProdEndpoint,
-    http: [port: @prod, transport_options: [socket_opts: so_reuseport()]],
-    url: [host: "example.com"],
-    server: true,
-    drainer: false,
-    render_errors: [accepts: ~w(html json)]
-  )
-
+    http: [port: @prod], url: [host: "example.com"], server: true, drainer: false,
+    render_errors: [accepts: ~w(html json)])
   Application.put_env(:endpoint_int, DevEndpoint,
-    http: [port: @dev, transport_options: [socket_opts: so_reuseport()]],
-    debug_errors: true,
-    drainer: false
-  )
+    http: [port: @dev], debug_errors: true, drainer: false)
 
   Application.put_env(:endpoint_int, ProdInet6Endpoint,
-    http: [port: @prod_inet6, transport_options: [socket_opts: [:inet6] ++ so_reuseport()]],
+    http: [port: @prod_inet6, transport_options: [socket_opts: [:inet6]]],
     url: [host: "example.com"],
-    server: true
-  )
+    server: true)
 
   defmodule Router do
     @moduledoc """
diff --git a/test/support/endpoint_helper.exs b/test/support/endpoint_helper.exs
index 8c2503904..ae1bd9a28 100644
--- a/test/support/endpoint_helper.exs
+++ b/test/support/endpoint_helper.exs
@@ -15,7 +15,7 @@ defmodule Phoenix.Integration.EndpointHelper do
   end
 
   defp listen_on_os_assigned_port(_) do
-    {:ok, socket} = :gen_tcp.listen(0, so_reuseport())
+    {:ok, socket} = :gen_tcp.listen(0, [])
     socket
   end
 
@@ -24,26 +24,4 @@ defmodule Phoenix.Integration.EndpointHelper do
     :gen_tcp.close(socket)
     port_number
   end
-
-  @doc """
-  Socket option to allow a port to be reused.
-
-  When provided as a socket option, this allows for a port to be bound to by
-  multiple processes and prevents `:eaddrinuse` errors. This is useful in
-  Phoenix's integration tests because in order to get an unused port number from
-  the OS in `get_unused_port_numbers/1` we have to open and close a socket,
-  which temporarily makes the port number unavailable to other processes while
-  the OS is shutting it down (the shutdown process continues even after
-  `:gen_tcp.close/1` returns). Trying to reuse the port number before this
-  shutdown process is complete causes `:eaddrinuse` errors, unless the original
-  socket and the new socket that is being opened are opened with the
-  `so_reuseport` option.
-  """
-  def so_reuseport do
-    case :os.type() do
-      {:unix, :linux} -> [{:raw, 1, 15, <<1::32-native>>}]
-      {:unix, :darwin} -> [{:raw, 65_535, 512, <<1::32-native>>}]
-      _ -> []
-    end
-  end
 end