Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set assetPrefix dynamically #3661

Merged
merged 3 commits into from
Feb 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,16 @@
"benchmark": "2.1.4",
"cheerio": "0.22.0",
"chromedriver": "2.32.3",
"clone": "2.1.1",
"coveralls": "2.13.1",
"cross-env": "5.0.5",
"express": "4.15.5",
"fkill": "5.1.0",
"get-port": "3.2.0",
"husky": "0.14.3",
"jest-cli": "21.2.0",
"lint-staged": "4.2.3",
"micro": "9.1.0",
"mkdirp": "0.5.1",
"node-fetch": "1.7.3",
"node-notifier": "5.1.2",
Expand Down
45 changes: 41 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<img width="112" alt="screen shot 2016-10-25 at 2 37 27 pm" src="https://cloud.githubusercontent.com/assets/13041/19686250/971bf7f8-9ac0-11e6-975c-188defd82df1.png">

[![NPM version](https://img.shields.io/npm/v/next.svg)](https://www.npmjs.com/package/next)
[![NPM version](https://img.shields.io/npm/v/next.svg)](https://www.npmjs.com/package/next)
[![Build Status](https://travis-ci.org/zeit/next.js.svg?branch=master)](https://travis-ci.org/zeit/next.js)
[![Build status](https://ci.appveyor.com/api/projects/status/gqp5hs71l3ebtx1r/branch/master?svg=true)](https://ci.appveyor.com/project/arunoda/next-js/branch/master)
[![Coverage Status](https://coveralls.io/repos/zeit/next.js/badge.svg?branch=master)](https://coveralls.io/r/zeit/next.js?branch=master)
Expand Down Expand Up @@ -224,7 +224,7 @@ export default () => (
```

In this case only the second `<meta name="viewport" />` is rendered.

_Note: The contents of `<head>` get cleared upon unmounting the component, so make sure each page completely defines what it needs in `<head>`, without making assumptions about what other pages added_

### Fetching data and component lifecycle
Expand Down Expand Up @@ -744,9 +744,9 @@ Then, change your `start` script to `NODE_ENV=production node server.js`.
#### Disabling file-system routing
By default, `Next` will serve each file in `/pages` under a pathname matching the filename (eg, `/pages/some-file.js` is served at `site.com/some-file`.

If your project uses custom routing, this behavior may result in the same content being served from multiple paths, which can present problems with SEO and UX.
If your project uses custom routing, this behavior may result in the same content being served from multiple paths, which can present problems with SEO and UX.

To disable this behavior & prevent routing based on files in `/pages`, simply set the following option in your `next.config.js`:
To disable this behavior & prevent routing based on files in `/pages`, simply set the following option in your `next.config.js`:

```js
// next.config.js
Expand All @@ -755,6 +755,43 @@ module.exports = {
}
```

#### Dynamic assetPrefix

Sometimes we need to set the `assetPrefix` dynamically. This is useful when changing the `assetPrefix` based on incoming requests.
For that, we can use `app.setAssetPrefix`.

Here's an example usage of it:

```js
const next = require('next')
const micro = require('micro')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
const server = micro((req, res) => {
// Add assetPrefix support based on the hostname
if (req.headers.host === 'my-app.com') {
app.setAssetPrefix('http://cdn.com/myapp')
} else {
app.setAssetPrefix('')
}

handleNextRequests(req, res)
})

server.listen(port, (err) => {
if (err) {
throw err
}

console.log(`> Ready on http://localhost:${port}`)
})
})

```

### Dynamic Import

Expand Down
10 changes: 6 additions & 4 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,10 @@ export default class Server {
hotReloader: this.hotReloader,
buildStats: this.buildStats,
buildId: this.buildId,
assetPrefix: this.config.assetPrefix.replace(/\/$/, ''),
availableChunks: dev ? {} : getAvailableChunks(this.dir, this.dist)
}

// With this, static assets will work across zones
asset.setAssetPrefix(this.config.assetPrefix)

this.setAssetPrefix(this.config.assetPrefix)
this.defineRoutes()
}

Expand Down Expand Up @@ -87,6 +84,11 @@ export default class Server {
return this.handleRequest.bind(this)
}

setAssetPrefix (prefix) {
this.renderOpts.assetPrefix = prefix.replace(/\/$/, '')
asset.setAssetPrefix(this.renderOpts.assetPrefix)
}

async prepare () {
if (this.hotReloader) {
await this.hotReloader.start()
Expand Down
3 changes: 3 additions & 0 deletions test/integration/custom-server/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default () => (
<div>My Homepage</div>
)
31 changes: 31 additions & 0 deletions test/integration/custom-server/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const micro = require('micro')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const dir = __dirname
const port = process.env.PORT || 3000

const app = next({ dev, dir })
const handleNextRequests = app.getRequestHandler()

app.prepare().then(() => {
const server = micro((req, res) => {
if (/setAssetPrefix/.test(req.url)) {
app.setAssetPrefix('https://cdn.com/myapp')
} else {
// This is to support multi-zones support in localhost
// and may be in staging deployments
app.setAssetPrefix('')
}

handleNextRequests(req, res)
})

server.listen(port, (err) => {
if (err) {
throw err
}

console.log(`> Ready on http://localhost:${port}`)
})
})
51 changes: 51 additions & 0 deletions test/integration/custom-server/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* global jasmine, describe, it, expect, beforeAll, afterAll */

import { join } from 'path'
import getPort from 'get-port'
import clone from 'clone'
import {
initNextServerScript,
killApp,
renderViaHTTP
} from 'next-test-utils'

const appDir = join(__dirname, '../')
let appPort
let server
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2

const context = {}

describe('Custom Server', () => {
beforeAll(async () => {
const scriptPath = join(appDir, 'server.js')
context.appPort = appPort = await getPort()
const env = clone(process.env)
env.PORT = `${appPort}`

server = await initNextServerScript(scriptPath, /Ready on/, env)
})
afterAll(() => killApp(server))

describe('with dynamic assetPrefix', () => {
it('should set the assetPrefix dynamically', async () => {
const normalUsage = await renderViaHTTP(appPort, '/')
expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)

const dynamicUsage = await renderViaHTTP(appPort, '/?setAssetPrefix=1')
expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
})

it('should set the assetPrefix to a given request', async () => {
for (let lc = 0; lc < 1000; lc++) {
const [normalUsage, dynamicUsage] = await Promise.all([
await renderViaHTTP(appPort, '/'),
await renderViaHTTP(appPort, '/?setAssetPrefix=1')
])

expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)
expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
}
})
})
})
30 changes: 30 additions & 0 deletions test/lib/next-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,36 @@ export const nextBuild = build
export const nextExport = _export
export const pkg = _pkg

export function initNextServerScript (scriptPath, successRegexp, env) {
return new Promise((resolve, reject) => {
const instance = spawn('node', [scriptPath], { env })

function handleStdout (data) {
const message = data.toString()
if (successRegexp.test(message)) {
resolve(instance)
}
process.stdout.write(message)
}

function handleStderr (data) {
process.stderr.write(data.toString())
}

instance.stdout.on('data', handleStdout)
instance.stderr.on('data', handleStderr)

instance.on('close', () => {
instance.stdout.removeListener('data', handleStdout)
instance.stderr.removeListener('data', handleStderr)
})

instance.on('error', (err) => {
reject(err)
})
})
}

export function renderViaAPI (app, pathname, query) {
const url = `${pathname}${query ? `?${qs.stringify(query)}` : ''}`
return app.renderToHTML({ url }, {}, pathname, query)
Expand Down
40 changes: 35 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,10 @@ builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"

bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"

cacache@^10.0.1:
version "10.0.2"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.2.tgz#105a93a162bbedf3a25da42e1939ed99ffb145f8"
Expand Down Expand Up @@ -1458,6 +1462,10 @@ cliui@^3.2.0:
strip-ansi "^3.0.1"
wrap-ansi "^2.0.0"

clone@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb"

clor@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/clor/-/clor-5.2.0.tgz#9ddc74e7e86728cfcd05a80546ba58d317b81035"
Expand Down Expand Up @@ -1541,7 +1549,7 @@ content-type-parser@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"

content-type@~1.0.2:
content-type@1.0.4, content-type@~1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"

Expand Down Expand Up @@ -2657,6 +2665,10 @@ get-own-enumerable-property-symbols@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b"

get-port@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"

get-stdin@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
Expand Down Expand Up @@ -2957,7 +2969,7 @@ iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"

iconv-lite@~0.4.13:
iconv-lite@0.4.19, iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"

Expand Down Expand Up @@ -3203,7 +3215,7 @@ is-resolvable@^1.0.0:
dependencies:
tryit "^1.0.1"

is-stream@^1.0.1, is-stream@^1.1.0:
is-stream@1.1.0, is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"

Expand Down Expand Up @@ -3961,6 +3973,15 @@ methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"

micro@9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/micro/-/micro-9.1.0.tgz#f2effba306639076e994c007c327dfc36a5185e9"
dependencies:
content-type "1.0.4"
is-stream "1.1.0"
mri "1.1.0"
raw-body "2.3.2"

micromatch@^2.1.5, micromatch@^2.3.11:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
Expand Down Expand Up @@ -4093,7 +4114,7 @@ move-concurrently@^1.0.1:
rimraf "^2.5.4"
run-queue "^1.0.3"

mri@^1.1.0:
mri@1.1.0, mri@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.0.tgz#5c0a3f29c8ccffbbb1ec941dcec09d71fa32f36a"

Expand Down Expand Up @@ -4769,6 +4790,15 @@ range-parser@^1.0.3, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"

raw-body@2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
dependencies:
bytes "3.0.0"
http-errors "1.6.2"
iconv-lite "0.4.19"
unpipe "1.0.0"

rc@^1.1.7:
version "1.2.2"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077"
Expand Down Expand Up @@ -5865,7 +5895,7 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"

unpipe@~1.0.0:
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"

Expand Down