Skip to content

Commit 2495316

Browse files
loganfsmythtimneutkens
authored andcommitted
Use custom Babel loader to avoid using separate Babel copies for loader and loader options (vercel#4417)
This resolves the > .value is not a valid Plugin property error showing up for people in vercel#4227 cc @timneutkens
1 parent f620b8f commit 2495316

File tree

10 files changed

+170
-66
lines changed

10 files changed

+170
-66
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"@babel/template": "7.0.0-beta.42",
6666
"ansi-html": "0.0.7",
6767
"babel-core": "7.0.0-bridge.0",
68-
"babel-loader": "8.0.0-beta.2",
68+
"babel-loader": "8.0.0-beta.3",
6969
"babel-plugin-react-require": "3.0.0",
7070
"babel-plugin-transform-react-remove-prop-types": "0.4.13",
7171
"case-sensitive-paths-webpack-plugin": "2.1.1",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import babelLoader from 'babel-loader'
2+
3+
module.exports = babelLoader.custom(babel => {
4+
const presetItem = babel.createConfigItem(require('../babel/preset'), {type: 'preset'})
5+
const hotLoaderItem = babel.createConfigItem(require('react-hot-loader/babel'), {type: 'plugin'})
6+
const reactJsxSourceItem = babel.createConfigItem(require('@babel/plugin-transform-react-jsx-source'), {type: 'plugin'})
7+
8+
const configs = new Set()
9+
10+
return {
11+
customOptions (opts) {
12+
const custom = {
13+
isServer: opts.isServer,
14+
dev: opts.dev
15+
}
16+
const loader = Object.assign({
17+
cacheDirectory: true
18+
}, opts)
19+
delete loader.isServer
20+
delete loader.dev
21+
22+
return { loader, custom }
23+
},
24+
config (cfg, {customOptions: {isServer, dev}}) {
25+
const options = Object.assign({}, cfg.options)
26+
if (cfg.hasFilesystemConfig()) {
27+
for (const file of [cfg.babelrc, cfg.config]) {
28+
if (file && !configs.has(file)) {
29+
configs.add(file)
30+
console.log(`> Using external babel configuration`)
31+
console.log(`> Location: "${file}"`)
32+
}
33+
}
34+
} else {
35+
// Add our default preset if the no "babelrc" found.
36+
options.presets = [...options.presets, presetItem]
37+
}
38+
39+
options.plugins = [
40+
...options.plugins,
41+
dev && !isServer && hotLoaderItem,
42+
dev && reactJsxSourceItem
43+
].filter(Boolean)
44+
45+
return options
46+
}
47+
}
48+
})

server/build/webpack.js

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import UglifyJSPlugin from 'uglifyjs-webpack-plugin'
55
import CaseSensitivePathPlugin from 'case-sensitive-paths-webpack-plugin'
66
import WriteFilePlugin from 'write-file-webpack-plugin'
77
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
8-
import {loadPartialConfig, createConfigItem} from '@babel/core'
98
import {getPages} from './webpack/utils'
109
import PagesPlugin from './plugins/pages-plugin'
1110
import NextJsSsrImportPlugin from './plugins/nextjs-ssr-import'
@@ -14,10 +13,6 @@ import UnlinkFilePlugin from './plugins/unlink-file-plugin'
1413
import PagesManifestPlugin from './plugins/pages-manifest-plugin'
1514
import BuildManifestPlugin from './plugins/build-manifest-plugin'
1615

17-
const presetItem = createConfigItem(require('./babel/preset'), {type: 'preset'})
18-
const hotLoaderItem = createConfigItem(require('react-hot-loader/babel'), {type: 'plugin'})
19-
const reactJsxSourceItem = createConfigItem(require('@babel/plugin-transform-react-jsx-source'), {type: 'plugin'})
20-
2116
const nextDir = path.join(__dirname, '..', '..', '..')
2217
const nextNodeModulesDir = path.join(nextDir, 'node_modules')
2318
const nextPagesDir = path.join(nextDir, 'pages')
@@ -30,37 +25,6 @@ const interpolateNames = new Map(defaultPages.map((p) => {
3025
return [path.join(nextPagesDir, p), `dist/bundles/pages/${p}`]
3126
}))
3227

33-
function babelConfig (dir, {isServer, dev}) {
34-
const mainBabelOptions = {
35-
cacheDirectory: true,
36-
presets: [],
37-
plugins: [
38-
dev && !isServer && hotLoaderItem,
39-
dev && reactJsxSourceItem
40-
].filter(Boolean)
41-
}
42-
43-
const filename = path.join(dir, 'filename.js')
44-
const externalBabelConfig = loadPartialConfig({ babelrc: true, filename })
45-
if (externalBabelConfig && externalBabelConfig.babelrc) {
46-
// Log it out once
47-
if (!isServer) {
48-
console.log(`> Using external babel configuration`)
49-
console.log(`> Location: "${externalBabelConfig.babelrc}"`)
50-
}
51-
mainBabelOptions.babelrc = true
52-
} else {
53-
mainBabelOptions.babelrc = false
54-
}
55-
56-
// Add our default preset if the no "babelrc" found.
57-
if (!mainBabelOptions.babelrc) {
58-
mainBabelOptions.presets.push(presetItem)
59-
}
60-
61-
return mainBabelOptions
62-
}
63-
6428
function externalsConfig (dir, isServer) {
6529
const externals = []
6630

@@ -96,12 +60,10 @@ function externalsConfig (dir, isServer) {
9660
}
9761

9862
export default async function getBaseWebpackConfig (dir, {dev = false, isServer = false, buildId, config}) {
99-
const babelLoaderOptions = babelConfig(dir, {dev, isServer})
100-
10163
const defaultLoaders = {
10264
babel: {
103-
loader: 'babel-loader',
104-
options: babelLoaderOptions
65+
loader: 'next-babel-loader',
66+
options: {dev, isServer}
10567
}
10668
}
10769

test/integration/babel/.babelrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": [
3+
"next/babel",
4+
"@babel/preset-flow"
5+
]
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This page is written in flowtype to test Babel's functionality
2+
import * as React from 'react'
3+
4+
type Props = {}
5+
6+
export default class MyComponent extends React.Component<Props> {
7+
render () {
8+
return <div id='text'>Test Babel</div>
9+
}
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"presets": [
3+
["next/babel", {
4+
"preset-env": {
5+
"modules": "commonjs"
6+
}
7+
}]
8+
]
9+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* global jasmine, describe, beforeAll, afterAll */
2+
3+
import { join } from 'path'
4+
import {
5+
renderViaHTTP,
6+
fetchViaHTTP,
7+
findPort,
8+
launchApp,
9+
killApp
10+
} from 'next-test-utils'
11+
12+
// test suits
13+
import rendering from './rendering'
14+
15+
const context = {}
16+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
17+
18+
describe('Babel', () => {
19+
beforeAll(async () => {
20+
context.appPort = await findPort()
21+
context.server = await launchApp(join(__dirname, '../'), context.appPort, true)
22+
23+
// pre-build all pages at the start
24+
await Promise.all([
25+
renderViaHTTP(context.appPort, '/')
26+
])
27+
})
28+
afterAll(() => killApp(context.server))
29+
30+
rendering(context, 'Rendering via HTTP', (p, q) => renderViaHTTP(context.appPort, p, q), (p, q) => fetchViaHTTP(context.appPort, p, q))
31+
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* global describe, it, expect */
2+
3+
import cheerio from 'cheerio'
4+
5+
export default function ({ app }, suiteName, render, fetch) {
6+
async function get$ (path, query) {
7+
const html = await render(path, query)
8+
return cheerio.load(html)
9+
}
10+
11+
describe(suiteName, () => {
12+
it('Should compile a page with flowtype correctly', async () => {
13+
const $ = await get$('/')
14+
expect($('#text').text()).toBe('Test Babel')
15+
})
16+
})
17+
}

test/integration/basic/test/hmr.js

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* global describe, it, expect */
22
import webdriver from 'next-webdriver'
3-
import { readFileSync, writeFileSync, renameSync } from 'fs'
3+
import { readFileSync, writeFileSync, renameSync, existsSync } from 'fs'
44
import { join } from 'path'
55
import { waitFor, check } from 'next-test-utils'
66
import cheerio from 'cheerio'
@@ -9,33 +9,39 @@ export default (context, renderViaHTTP) => {
99
describe('Hot Module Reloading', () => {
1010
describe('delete a page and add it back', () => {
1111
it('should load the page properly', async () => {
12-
const browser = await webdriver(context.appPort, '/hmr/contact')
13-
const text = await browser
14-
.elementByCss('p').text()
15-
expect(text).toBe('This is the contact page.')
16-
1712
const contactPagePath = join(__dirname, '../', 'pages', 'hmr', 'contact.js')
1813
const newContactPagePath = join(__dirname, '../', 'pages', 'hmr', '_contact.js')
1914

20-
// Rename the file to mimic a deleted page
21-
renameSync(contactPagePath, newContactPagePath)
15+
try {
16+
const browser = await webdriver(context.appPort, '/hmr/contact')
17+
const text = await browser
18+
.elementByCss('p').text()
19+
expect(text).toBe('This is the contact page.')
2220

23-
// wait until the 404 page comes
24-
await check(
25-
() => browser.elementByCss('body').text(),
26-
/This page could not be found/
27-
)
21+
// Rename the file to mimic a deleted page
22+
renameSync(contactPagePath, newContactPagePath)
2823

29-
// Rename the file back to the original filename
30-
renameSync(newContactPagePath, contactPagePath)
24+
// wait until the 404 page comes
25+
await check(
26+
() => browser.elementByCss('body').text(),
27+
/(This page could not be found|ENOENT)/
28+
)
3129

32-
// wait until the page comes back
33-
await check(
34-
() => browser.elementByCss('body').text(),
35-
/This is the contact page/
36-
)
30+
// Rename the file back to the original filename
31+
renameSync(newContactPagePath, contactPagePath)
3732

38-
browser.close()
33+
// wait until the page comes back
34+
await check(
35+
() => browser.elementByCss('body').text(),
36+
/This is the contact page/
37+
)
38+
39+
browser.close()
40+
} finally {
41+
if (existsSync(newContactPagePath)) {
42+
renameSync(newContactPagePath, contactPagePath)
43+
}
44+
}
3945
})
4046
})
4147

yarn.lock

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,13 +1171,14 @@ babel-jest@21.2.0, babel-jest@^21.2.0:
11711171
babel-plugin-istanbul "^4.0.0"
11721172
babel-preset-jest "^21.2.0"
11731173

1174-
babel-loader@8.0.0-beta.2:
1175-
version "8.0.0-beta.2"
1176-
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.0-beta.2.tgz#4d5b67c964dc8c9cba866fd13d6b90df3acf8723"
1174+
babel-loader@8.0.0-beta.3:
1175+
version "8.0.0-beta.3"
1176+
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.0-beta.3.tgz#49efeea6e8058d5af860a18a6de88b8c1450645b"
11771177
dependencies:
11781178
find-cache-dir "^1.0.0"
11791179
loader-utils "^1.0.2"
11801180
mkdirp "^0.5.1"
1181+
util.promisify "^1.0.0"
11811182

11821183
babel-messages@^6.23.0:
11831184
version "6.23.0"
@@ -2544,7 +2545,7 @@ error-stack-parser@^2.0.0:
25442545
dependencies:
25452546
stackframe "^1.0.3"
25462547

2547-
es-abstract@^1.7.0:
2548+
es-abstract@^1.5.1, es-abstract@^1.7.0:
25482549
version "1.11.0"
25492550
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681"
25502551
dependencies:
@@ -5341,6 +5342,13 @@ object.assign@^4.0.4:
53415342
has-symbols "^1.0.0"
53425343
object-keys "^1.0.11"
53435344

5345+
object.getownpropertydescriptors@^2.0.3:
5346+
version "2.0.3"
5347+
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
5348+
dependencies:
5349+
define-properties "^1.1.2"
5350+
es-abstract "^1.5.1"
5351+
53445352
object.omit@^2.0.0:
53455353
version "2.0.1"
53465354
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -7439,6 +7447,13 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1:
74397447
version "1.0.2"
74407448
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
74417449

7450+
util.promisify@^1.0.0:
7451+
version "1.0.0"
7452+
resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
7453+
dependencies:
7454+
define-properties "^1.1.2"
7455+
object.getownpropertydescriptors "^2.0.3"
7456+
74427457
util@0.10.3, util@^0.10.3:
74437458
version "0.10.3"
74447459
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"

0 commit comments

Comments
 (0)