1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Convert babel plugins to typescript (#5789)

Slowly moving files over 💯
This commit is contained in:
Tim Neutkens 2018-12-02 18:30:00 +01:00 committed by GitHub
parent e43d21fdf0
commit a9cf735f50
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 175 additions and 124 deletions

View file

@ -1,8 +1,11 @@
import {PluginObj} from '@babel/core'
import {NodePath} from '@babel/traverse'
import {ImportDeclaration} from '@babel/types'
// Rewrite imports using next/<something> to next-server/<something>
export default function ({ types: t, template }) {
export default function NextToNextServer (): PluginObj {
return {
visitor: {
ImportDeclaration (path) {
ImportDeclaration (path: NodePath<ImportDeclaration>) {
const source = path.node.source.value
if (source === 'next/asset') {
path.node.source.value = 'next-server/asset'

View file

@ -23,10 +23,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
// Modified to put `webpack` and `modules` under `loadableGenerated` to be backwards compatible with next/dynamic which has a `modules` key
// Modified to support `dynamic(import('something'))` and `dynamic(import('something'), options)
export default function ({ types: t, template }) {
import {PluginObj} from '@babel/core'
import {NodePath} from '@babel/traverse'
import * as BabelTypes from '@babel/types'
export default function ({ types: t }: {types: typeof BabelTypes}): PluginObj {
return {
visitor: {
ImportDeclaration (path) {
ImportDeclaration (path: NodePath<BabelTypes.ImportDeclaration>) {
let source = path.node.source.value
if (source !== 'next/dynamic') return
@ -36,8 +40,12 @@ export default function ({ types: t, template }) {
if (!defaultSpecifier) return
let bindingName = defaultSpecifier.node.local.name
let binding = path.scope.getBinding(bindingName)
const bindingName = defaultSpecifier.node.local.name
const binding = path.scope.getBinding(bindingName)
if(!binding) {
return
}
binding.referencePaths.forEach(refPath => {
let callExpression = refPath.parentPath
@ -53,20 +61,22 @@ export default function ({ types: t, template }) {
if (!callExpression.isCallExpression()) return
let args = callExpression.get('arguments')
if (args.length > 2) throw callExpression.error
let loader
let options
if (args.length > 2) {
throw callExpression.buildCodeFrameError('next/dynamic only accepts 2 arguments')
}
if (!args[0]) {
return
}
let loader
let options
if (args[0].isObjectExpression()) {
options = args[0]
} else {
if (!args[1]) {
callExpression.pushContainer('arguments', t.objectExpression([]))
callExpression.node.arguments.push(t.objectExpression([]))
}
// This is needed as the code is modified above
args = callExpression.get('arguments')
@ -77,10 +87,10 @@ export default function ({ types: t, template }) {
if (!options.isObjectExpression()) return
let properties = options.get('properties')
let propertiesMap = {}
let propertiesMap: {[key: string]: NodePath<BabelTypes.ObjectProperty | BabelTypes.ObjectMethod | BabelTypes.SpreadProperty>} = {}
properties.forEach(property => {
let key = property.get('key')
const key: any = property.get('key')
propertiesMap[key.node.name] = property
})
@ -96,50 +106,50 @@ export default function ({ types: t, template }) {
loader = propertiesMap.modules.get('value')
}
let loaderMethod = loader
let dynamicImports = []
if(!loader || Array.isArray(loader)) {
return
}
const dynamicImports: BabelTypes.StringLiteral[] = []
loaderMethod.traverse({
loader.traverse({
Import (path) {
dynamicImports.push(path.parentPath)
const args = path.parentPath.get('arguments')
if(!Array.isArray(args)) return
const node: any = args[0].node
dynamicImports.push(node)
}
})
if (!dynamicImports.length) return
options.pushContainer(
'properties',
t.objectProperty(
t.identifier('loadableGenerated'),
t.objectExpression([
t.objectProperty(
t.identifier('webpack'),
t.arrowFunctionExpression(
[],
t.arrayExpression(
dynamicImports.map(dynamicImport => {
return t.callExpression(
t.memberExpression(
t.identifier('require'),
t.identifier('resolveWeak')
),
[dynamicImport.get('arguments')[0].node]
)
})
)
)
),
t.objectProperty(
t.identifier('modules'),
options.node.properties.push(t.objectProperty(
t.identifier('loadableGenerated'),
t.objectExpression([
t.objectProperty(
t.identifier('webpack'),
t.arrowFunctionExpression(
[],
t.arrayExpression(
dynamicImports.map(dynamicImport => {
return dynamicImport.get('arguments')[0].node
return t.callExpression(
t.memberExpression(
t.identifier('require'),
t.identifier('resolveWeak')
),
[dynamicImport]
)
})
)
)
])
)
)
),
t.objectProperty(
t.identifier('modules'),
t.arrayExpression(
dynamicImports
)
)
])
))
// Turns `dynamic(import('something'))` into `dynamic(() => import('something'))` for backwards compat.
// This is the replicate the behavior in versions below Next.js 7 where we magically handled not executing the `import()` too.

View file

@ -1,63 +0,0 @@
const env = process.env.NODE_ENV
const isProduction = env === 'production'
const isDevelopment = env === 'development'
const isTest = env === 'test'
// Resolve styled-jsx plugins
function styledJsxOptions (opts) {
if (!opts) {
return {}
}
if (!Array.isArray(opts.plugins)) {
return opts
}
opts.plugins = opts.plugins.map(plugin => {
if (Array.isArray(plugin)) {
const [name, options] = plugin
return [
require.resolve(name),
options
]
}
return require.resolve(plugin)
})
return opts
}
module.exports = (context, opts = {}) => ({
presets: [
[require('@babel/preset-env').default, {
// In the test environment `modules` is often needed to be set to true, babel figures that out by itself using the `'auto'` option
// In production/development this option is set to `false` so that webpack can handle import/export with tree-shaking
modules: isDevelopment || isProduction ? false : 'auto',
...opts['preset-env']
}],
[require('@babel/preset-react'), {
// This adds @babel/plugin-transform-react-jsx-source and
// @babel/plugin-transform-react-jsx-self automatically in development
development: isDevelopment || isTest,
...opts['preset-react']
}]
],
plugins: [
require('babel-plugin-react-require'),
require('@babel/plugin-syntax-dynamic-import'),
require('./plugins/react-loadable-plugin'),
require('./plugins/next-to-next-server'),
[require('@babel/plugin-proposal-class-properties'), opts['class-properties'] || {}],
require('@babel/plugin-proposal-object-rest-spread'),
[require('@babel/plugin-transform-runtime'), {
corejs: 2,
helpers: true,
regenerator: true,
useESModules: !isTest,
...opts['transform-runtime']
}],
[require('styled-jsx/babel'), styledJsxOptions(opts['styled-jsx'])],
process.env.NODE_ENV === 'production' && require('babel-plugin-transform-react-remove-prop-types')
].filter(Boolean)
})

View file

@ -0,0 +1,84 @@
import {PluginItem} from '@babel/core'
const env = process.env.NODE_ENV
const isProduction = env === 'production'
const isDevelopment = env === 'development'
const isTest = env === 'test'
type StyledJsxPlugin = [string, any] | string
type StyledJsxBabelOptions = {
plugins?: StyledJsxPlugin[]
} | undefined
// Resolve styled-jsx plugins
function styledJsxOptions (options: StyledJsxBabelOptions) {
if (!options) {
return {}
}
if (!Array.isArray(options.plugins)) {
return options
}
options.plugins = options.plugins.map((plugin: StyledJsxPlugin): StyledJsxPlugin => {
if (Array.isArray(plugin)) {
const [name, options] = plugin
return [
require.resolve(name),
options
]
}
return require.resolve(plugin)
})
return options
}
type NextBabelPresetOptions = {
'preset-env'?: any,
'preset-react'?: any,
'class-properties'?: any,
'transform-runtime'?: any,
'styled-jsx'?: StyledJsxBabelOptions
}
type BabelPreset = {
presets?: PluginItem[] | null,
plugins?: PluginItem[] | null
}
module.exports = (context: any, options: NextBabelPresetOptions = {}): BabelPreset => {
return {
presets: [
[require('@babel/preset-env').default, {
// In the test environment `modules` is often needed to be set to true, babel figures that out by itself using the `'auto'` option
// In production/development this option is set to `false` so that webpack can handle import/export with tree-shaking
modules: isDevelopment || isProduction ? false : 'auto',
...options['preset-env']
}],
[require('@babel/preset-react'), {
// This adds @babel/plugin-transform-react-jsx-source and
// @babel/plugin-transform-react-jsx-self automatically in development
development: isDevelopment || isTest,
...options['preset-react']
}]
],
plugins: [
require('babel-plugin-react-require'),
require('@babel/plugin-syntax-dynamic-import'),
require('./plugins/react-loadable-plugin'),
require('./plugins/next-to-next-server'),
[require('@babel/plugin-proposal-class-properties'), options['class-properties'] || {}],
require('@babel/plugin-proposal-object-rest-spread'),
[require('@babel/plugin-transform-runtime'), {
corejs: 2,
helpers: true,
regenerator: true,
useESModules: !isTest,
...options['transform-runtime']
}],
[require('styled-jsx/babel'), styledJsxOptions(options['styled-jsx'])],
process.env.NODE_ENV === 'production' && require('babel-plugin-transform-react-remove-prop-types')
].filter(Boolean)
}
}

View file

@ -0,0 +1,13 @@
export async function generateBuildId (generate: () => string|null, fallback: () => string): Promise<string> {
let buildId = await generate()
// If there's no buildId defined we'll fall back
if (buildId === null) {
buildId = fallback()
}
if (typeof buildId !== 'string') {
throw new Error('generateBuildId did not return a string. https://err.sh/zeit/next.js/generatebuildid-not-a-string')
}
return buildId.trim()
}

View file

@ -6,24 +6,11 @@ import nanoid from 'nanoid'
import loadConfig from 'next-server/next-config'
import { PHASE_PRODUCTION_BUILD, BUILD_ID_FILE } from 'next-server/constants'
import getBaseWebpackConfig from './webpack'
import {generateBuildId} from './generate-build-id'
const access = promisify(fs.access)
const writeFile = promisify(fs.writeFile)
async function generateBuildId (generate, fallback) {
let buildId = await generate()
// If there's no buildId defined we'll fall back
if (buildId === null) {
buildId = fallback()
}
if (typeof buildId !== 'string') {
throw new Error('generateBuildId did not return a string. https://err.sh/zeit/next.js/generatebuildid-not-a-string')
}
return buildId.trim()
}
async function ensureProjectDirectoryIsWriteAble (dir) {
try {
await access(dir, (fs.constants || fs).W_OK)

View file

@ -94,6 +94,12 @@
"@taskr/clear": "1.1.0",
"@taskr/esnext": "1.1.0",
"@taskr/watch": "1.1.0",
"@types/babel__core": "7.0.4",
"@types/babel__traverse": "7.0.3",
"@types/nanoid": "1.2.0",
"@types/babel-types": "7.0.4",
"@types/babel__generator": "7.0.1",
"@types/babel__template": "7.0.1",
"taskr": "1.1.0",
"typescript": "3.1.6"
},

View file

@ -5,6 +5,17 @@
"module": "esnext",
"target": "ES2017",
"esModuleInterop": true,
"jsx": "react"
"jsx": "react",
"strictNullChecks": true,
"noImplicitAny": true,
"baseUrl": "../..",
"paths": {
"@babel/types": [
"babel-types/index.d.ts",
"@types/babel-types/index.d.ts",
"node_modules/@types/babel-types/index.d.ts",
"packages/next/node_modules/@types/babel-types/index.d.ts"
]
}
}
}