Clear stale files from Next.js' babel-loader cache (#7221)
* Move babel-loader into next all the way converting it to TypeScript and added tracking of babel-loader cache so we can clear previous files * Add license from babel-loader * Apply suggestions from code review Co-Authored-By: ijjk <jj@jjsweb.site> * Make sure to catch errors in next-babel-loader
This commit is contained in:
parent
064be18039
commit
8b92b8b7ce
11 changed files with 459 additions and 132 deletions
|
@ -6,6 +6,7 @@ import {
|
|||
import loadConfig from 'next-server/next-config'
|
||||
import nanoid from 'next/dist/compiled/nanoid/index.js'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
import formatWebpackMessages from '../client/dev-error-overlay/format-webpack-messages'
|
||||
import { recursiveDelete } from '../lib/recursive-delete'
|
||||
|
@ -25,6 +26,11 @@ import {
|
|||
import getBaseWebpackConfig from './webpack-config'
|
||||
import { exportManifest, getPageChunks } from './webpack/plugins/chunk-graph-plugin'
|
||||
import { writeBuildId } from './write-build-id'
|
||||
import { recursiveReadDir } from '../lib/recursive-readdir'
|
||||
import { usedBabelCacheFiles } from './webpack/loaders/next-babel-loader/cache'
|
||||
import { promisify } from 'util'
|
||||
|
||||
const unlink = promisify(fs.unlink)
|
||||
|
||||
export default async function build(dir: string, conf = null): Promise<void> {
|
||||
if (!(await isWriteable(dir))) {
|
||||
|
@ -278,5 +284,19 @@ export default async function build(dir: string, conf = null): Promise<void> {
|
|||
await flyingShuttle.save()
|
||||
}
|
||||
|
||||
// to prevent persisted caches from growing massively
|
||||
// we clear un-used files
|
||||
const babelCacheDir = path.join(distDir, 'cache/next-babel-loader')
|
||||
let babelCacheToClear = (await recursiveReadDir(babelCacheDir, /.*\.js/))
|
||||
.map(file => path.join(babelCacheDir, file))
|
||||
|
||||
babelCacheToClear = babelCacheToClear.filter((file: string) => {
|
||||
return !usedBabelCacheFiles.has(file)
|
||||
})
|
||||
|
||||
for (const file of babelCacheToClear) {
|
||||
await unlink(file)
|
||||
}
|
||||
|
||||
await writeBuildId(distDir, buildId, selectivePageBuilding)
|
||||
}
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
import hash from 'string-hash'
|
||||
import { join, basename } from 'path'
|
||||
import babelLoader from 'babel-loader'
|
||||
|
||||
// increment 'a' to invalidate cache
|
||||
const cacheKey = 'babel-cache-' + 'a' + '-'
|
||||
|
||||
module.exports = babelLoader.custom(babel => {
|
||||
const presetItem = babel.createConfigItem(require('../../babel/preset'), { type: 'preset' })
|
||||
const applyCommonJs = babel.createConfigItem(require('../../babel/plugins/commonjs'), { type: 'plugin' })
|
||||
const commonJsItem = babel.createConfigItem(require('@babel/plugin-transform-modules-commonjs'), { type: 'plugin' })
|
||||
|
||||
const configs = new Set()
|
||||
|
||||
return {
|
||||
customOptions (opts) {
|
||||
const custom = {
|
||||
isServer: opts.isServer,
|
||||
asyncToPromises: opts.asyncToPromises
|
||||
}
|
||||
const filename = join(opts.cwd, 'noop.js')
|
||||
const loader = Object.assign({
|
||||
cacheCompression: false,
|
||||
cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'),
|
||||
cacheIdentifier: cacheKey + JSON.stringify(
|
||||
babel.loadPartialConfig({
|
||||
filename,
|
||||
cwd: opts.cwd,
|
||||
sourceFileName: filename
|
||||
}).options
|
||||
)
|
||||
}, opts)
|
||||
|
||||
delete loader.isServer
|
||||
delete loader.asyncToPromises
|
||||
delete loader.distDir
|
||||
return { loader, custom }
|
||||
},
|
||||
config (cfg, { source, customOptions: { isServer, asyncToPromises } }) {
|
||||
const filename = this.resourcePath
|
||||
const options = Object.assign({}, cfg.options)
|
||||
if (cfg.hasFilesystemConfig()) {
|
||||
for (const file of [cfg.babelrc, cfg.config]) {
|
||||
// We only log for client compilation otherwise there will be double output
|
||||
if (file && !isServer && !configs.has(file)) {
|
||||
configs.add(file)
|
||||
console.log(`> Using external babel configuration`)
|
||||
console.log(`> Location: "${file}"`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add our default preset if the no "babelrc" found.
|
||||
options.presets = [...options.presets, presetItem]
|
||||
}
|
||||
|
||||
if (!isServer && source.indexOf('next/amp')) {
|
||||
const dropClientPlugin = babel.createConfigItem([require('../../babel/plugins/next-drop-client-page'), {}], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(dropClientPlugin)
|
||||
}
|
||||
|
||||
if (isServer && source.indexOf('next/data') !== -1) {
|
||||
const nextDataPlugin = babel.createConfigItem([require('../../babel/plugins/next-data'), { key: basename(filename) + '-' + hash(filename) }], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(nextDataPlugin)
|
||||
}
|
||||
|
||||
if (asyncToPromises) {
|
||||
const asyncToPromisesPlugin = babel.createConfigItem(['babel-plugin-transform-async-to-promises', {
|
||||
inlineHelpers: true
|
||||
}], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(asyncToPromisesPlugin)
|
||||
|
||||
const regeneratorPlugin = options.plugins.find(plugin => {
|
||||
return plugin[0] === require('@babel/plugin-transform-runtime')
|
||||
})
|
||||
if (regeneratorPlugin) {
|
||||
regeneratorPlugin[1].regenerator = false
|
||||
}
|
||||
|
||||
const babelPresetEnv = (options.presets || []).find((preset = []) => {
|
||||
return preset[0] === require('@babel/preset-env').default
|
||||
})
|
||||
if (babelPresetEnv) {
|
||||
babelPresetEnv[1].exclude = (options.presets[0][1].exclude || []).concat([
|
||||
'transform-typeof-symbol',
|
||||
'transform-regenerator',
|
||||
'transform-async-to-generator'
|
||||
])
|
||||
.filter('transform-typeof-symbol')
|
||||
}
|
||||
}
|
||||
|
||||
// If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements
|
||||
// That break webpack, since webpack doesn't support combining commonjs and esmodules
|
||||
if (source.indexOf('module.exports') !== -1) {
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(applyCommonJs)
|
||||
}
|
||||
|
||||
// As next-server/lib has stateful modules we have to transpile commonjs
|
||||
options.overrides = [
|
||||
...(options.overrides || []),
|
||||
{
|
||||
test: [
|
||||
/next-server[\\/]dist[\\/]lib/,
|
||||
/next[\\/]dist[\\/]client/,
|
||||
/next[\\/]dist[\\/]pages/
|
||||
],
|
||||
plugins: [
|
||||
commonJsItem
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
return options
|
||||
}
|
||||
}
|
||||
})
|
195
packages/next/build/webpack/loaders/next-babel-loader.ts
Normal file
195
packages/next/build/webpack/loaders/next-babel-loader.ts
Normal file
|
@ -0,0 +1,195 @@
|
|||
import hash from 'string-hash'
|
||||
import * as babel from '@babel/core'
|
||||
import { loader } from 'webpack'
|
||||
import { join, basename } from 'path'
|
||||
import loaderUtils from 'loader-utils'
|
||||
import cache from './next-babel-loader/cache'
|
||||
import transform, { version as transformVersion } from './next-babel-loader/transform'
|
||||
|
||||
// increment 'a' to invalidate cache
|
||||
const cacheKey = 'babel-cache-' + 'b' + '-'
|
||||
const configs = new Set()
|
||||
|
||||
const presetItem = babel.createConfigItem(require('../../babel/preset'), { type: 'preset' })
|
||||
const applyCommonJs = babel.createConfigItem(require('../../babel/plugins/commonjs'), { type: 'plugin' })
|
||||
const commonJsItem = babel.createConfigItem(require('@babel/plugin-transform-modules-commonjs'), { type: 'plugin' })
|
||||
|
||||
const nextBabelLoader: loader.Loader = function (source, inputSourceMap) {
|
||||
const callback = this.async()!
|
||||
const filename = this.resourcePath;
|
||||
let loaderOptions = loaderUtils.getOptions(this) || {};
|
||||
const { isServer, asyncToPromises, distDir } = loaderOptions
|
||||
|
||||
// Standardize on 'sourceMaps' as the key passed through to Webpack, so that
|
||||
// users may safely use either one alongside our default use of
|
||||
// 'this.sourceMap' below without getting error about conflicting aliases.
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(loaderOptions, "sourceMap") &&
|
||||
!Object.prototype.hasOwnProperty.call(loaderOptions, "sourceMaps")
|
||||
) {
|
||||
loaderOptions = Object.assign({}, loaderOptions, {
|
||||
sourceMaps: loaderOptions.sourceMap,
|
||||
});
|
||||
delete loaderOptions.sourceMap;
|
||||
}
|
||||
|
||||
const programmaticOptions = Object.assign({}, loaderOptions, {
|
||||
filename,
|
||||
inputSourceMap: inputSourceMap || undefined,
|
||||
|
||||
// Set the default sourcemap behavior based on Webpack's mapping flag,
|
||||
// but allow users to override if they want.
|
||||
sourceMaps:
|
||||
loaderOptions.sourceMaps === undefined
|
||||
? this.sourceMap
|
||||
: loaderOptions.sourceMaps,
|
||||
|
||||
// Ensure that Webpack will get a full absolute path in the sourcemap
|
||||
// so that it can properly map the module back to its internal cached
|
||||
// modules.
|
||||
sourceFileName: filename,
|
||||
});
|
||||
// Remove loader related options
|
||||
delete programmaticOptions.cacheDirectory;
|
||||
delete programmaticOptions.cacheIdentifier;
|
||||
delete programmaticOptions.cacheCompression;
|
||||
delete programmaticOptions.isServer
|
||||
delete programmaticOptions.asyncToPromises
|
||||
delete programmaticOptions.distDir
|
||||
|
||||
const config: any = babel.loadPartialConfig(programmaticOptions);
|
||||
if (config) {
|
||||
let options = config.options;
|
||||
|
||||
if (config.hasFilesystemConfig()) {
|
||||
for (const file of [config.babelrc, config.config]) {
|
||||
// We only log for client compilation otherwise there will be double output
|
||||
if (file && !isServer && !configs.has(file)) {
|
||||
configs.add(file)
|
||||
console.log(`> Using external babel configuration`)
|
||||
console.log(`> Location: "${file}"`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add our default preset if the no "babelrc" found.
|
||||
options.presets = [...options.presets, presetItem]
|
||||
}
|
||||
|
||||
if (!isServer && source.toString().indexOf('next/amp')) {
|
||||
const dropClientPlugin = babel.createConfigItem([require('../../babel/plugins/next-drop-client-page'), {}], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(dropClientPlugin)
|
||||
}
|
||||
|
||||
if (isServer && source.toString().indexOf('next/data') !== -1) {
|
||||
const nextDataPlugin = babel.createConfigItem([require('../../babel/plugins/next-data'), { key: basename(filename) + '-' + hash(filename) }], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(nextDataPlugin)
|
||||
}
|
||||
|
||||
if (asyncToPromises) {
|
||||
const asyncToPromisesPlugin = babel.createConfigItem(['babel-plugin-transform-async-to-promises', {
|
||||
inlineHelpers: true
|
||||
}], { type: 'plugin' })
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(asyncToPromisesPlugin)
|
||||
|
||||
const regeneratorPlugin = options.plugins.find((plugin: any) => {
|
||||
return plugin[0] === require('@babel/plugin-transform-runtime')
|
||||
})
|
||||
if (regeneratorPlugin) {
|
||||
regeneratorPlugin[1].regenerator = false
|
||||
}
|
||||
|
||||
const babelPresetEnv = (options.presets || []).find((preset: any = []) => {
|
||||
return preset[0] === require('@babel/preset-env').default
|
||||
})
|
||||
if (babelPresetEnv) {
|
||||
babelPresetEnv[1].exclude = (options.presets[0][1].exclude || []).concat([
|
||||
'transform-typeof-symbol',
|
||||
'transform-regenerator',
|
||||
'transform-async-to-generator'
|
||||
])
|
||||
.filter('transform-typeof-symbol')
|
||||
}
|
||||
}
|
||||
|
||||
// If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements
|
||||
// That break webpack, since webpack doesn't support combining commonjs and esmodules
|
||||
if (source.toString().indexOf('module.exports') !== -1) {
|
||||
options.plugins = options.plugins || []
|
||||
options.plugins.push(applyCommonJs)
|
||||
}
|
||||
|
||||
// As next-server/lib has stateful modules we have to transpile commonjs
|
||||
options.overrides = [
|
||||
...(options.overrides || []),
|
||||
{
|
||||
test: [
|
||||
/next-server[\\/]dist[\\/]lib/,
|
||||
/next[\\/]dist[\\/]client/,
|
||||
/next[\\/]dist[\\/]pages/
|
||||
],
|
||||
plugins: [
|
||||
commonJsItem
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
if (options.sourceMaps === "inline") {
|
||||
// Babel has this weird behavior where if you set "inline", we
|
||||
// inline the sourcemap, and set 'result.map = null'. This results
|
||||
// in bad behavior from Babel since the maps get put into the code,
|
||||
// which Webpack does not expect, and because the map we return to
|
||||
// Webpack is null, which is also bad. To avoid that, we override the
|
||||
// behavior here so "inline" just behaves like 'true'.
|
||||
options.sourceMaps = true;
|
||||
}
|
||||
|
||||
const {
|
||||
cacheDirectory = join(distDir, 'cache', 'next-babel-loader'),
|
||||
cacheIdentifier = JSON.stringify({
|
||||
options,
|
||||
cacheKey,
|
||||
"@babel/core": transformVersion,
|
||||
})
|
||||
} = loaderOptions;
|
||||
|
||||
const addDependency = (dep: string) => this.addDependency(dep)
|
||||
|
||||
async function getResult() {
|
||||
let result;
|
||||
if (cacheDirectory) {
|
||||
result = await cache({
|
||||
source,
|
||||
options,
|
||||
transform,
|
||||
cacheDirectory,
|
||||
cacheIdentifier,
|
||||
});
|
||||
} else {
|
||||
result = await transform(source.toString(), options);
|
||||
}
|
||||
|
||||
// TODO: Babel should really provide the full list of config files that
|
||||
// were used so that this can also handle files loaded with 'extends'.
|
||||
if (typeof config.babelrc === "string") {
|
||||
addDependency(config.babelrc);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
const { code, map } = result;
|
||||
callback(null, code, map)
|
||||
return
|
||||
}
|
||||
}
|
||||
getResult.bind(this)().catch((err: any) => callback(err))
|
||||
return
|
||||
}
|
||||
|
||||
// If the file was ignored, pass through the original content.
|
||||
callback(null, source, inputSourceMap);
|
||||
return
|
||||
}
|
||||
|
||||
export default nextBabelLoader
|
|
@ -0,0 +1,34 @@
|
|||
const STRIP_FILENAME_RE = /^[^:]+: /;
|
||||
|
||||
const format = (err: any) => {
|
||||
if (err instanceof SyntaxError) {
|
||||
err.name = "SyntaxError";
|
||||
err.message = err.message.replace(STRIP_FILENAME_RE, "");
|
||||
|
||||
// @ts-ignore
|
||||
err.hideStack = true;
|
||||
} else if (err instanceof TypeError) {
|
||||
// @ts-ignore
|
||||
err.name = null;
|
||||
err.message = err.message.replace(STRIP_FILENAME_RE, "");
|
||||
// @ts-ignore
|
||||
err.hideStack = true;
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
export default class LoaderError extends Error {
|
||||
name: string
|
||||
hideStack: any
|
||||
|
||||
constructor(err: any) {
|
||||
super();
|
||||
const { name, message, codeFrame, hideStack } = format(err);
|
||||
|
||||
this.name = "BabelLoaderError";
|
||||
this.message = `${name ? `${name}: ` : ""}${message}\n\n${codeFrame}\n`;
|
||||
this.hideStack = hideStack;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2014-2019 Luís Couto <hello@luiscouto.pt>
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
156
packages/next/build/webpack/loaders/next-babel-loader/cache.ts
Normal file
156
packages/next/build/webpack/loaders/next-babel-loader/cache.ts
Normal file
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* Filesystem Cache
|
||||
*
|
||||
* Given a file and a transform function, cache the result into files
|
||||
* or retrieve the previously cached files if the given file is already known.
|
||||
*
|
||||
* @see https://github.com/babel/babel-loader/issues/34
|
||||
* @see https://github.com/babel/babel-loader/pull/41
|
||||
*/
|
||||
import fs from "fs"
|
||||
import os from "os"
|
||||
import path from "path"
|
||||
import crypto from "crypto"
|
||||
import mkdirpOrig from "mkdirp"
|
||||
import { promisify } from "util"
|
||||
import transform from './transform'
|
||||
|
||||
// Lazily instantiated when needed
|
||||
let defaultCacheDirectory: any = null;
|
||||
|
||||
const readFile = promisify(fs.readFile);
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
const mkdirp = promisify(mkdirpOrig);
|
||||
|
||||
export const usedBabelCacheFiles: Set<String> = new Set()
|
||||
|
||||
/**
|
||||
* Read the contents from the compressed file.
|
||||
*
|
||||
* @async
|
||||
* @params {String} filename
|
||||
*/
|
||||
async function read(filename: string) {
|
||||
const data = await readFile(filename);
|
||||
const content = data;
|
||||
|
||||
usedBabelCacheFiles.add(filename)
|
||||
return JSON.parse(content.toString());
|
||||
};
|
||||
|
||||
/**
|
||||
* Write contents into a compressed file.
|
||||
*/
|
||||
async function write(filename: string, result: any) {
|
||||
const content = JSON.stringify(result);
|
||||
usedBabelCacheFiles.add(filename)
|
||||
return await writeFile(filename, content);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the filename for the cached file
|
||||
*/
|
||||
function filename(source: string, identifier: any, options: any): string {
|
||||
const hash = crypto.createHash("md4");
|
||||
|
||||
const contents = JSON.stringify({ source, options, identifier });
|
||||
|
||||
hash.update(contents);
|
||||
|
||||
return hash.digest("hex") + ".json";
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the cache
|
||||
*/
|
||||
async function handleCache(directory: string, params: any): Promise<any> {
|
||||
const {
|
||||
source,
|
||||
options = {},
|
||||
cacheIdentifier,
|
||||
cacheDirectory,
|
||||
} = params;
|
||||
|
||||
const file = path.join(directory, filename(source, cacheIdentifier, options));
|
||||
|
||||
try {
|
||||
// No errors mean that the file was previously cached
|
||||
// we just need to return it
|
||||
return await read(file);
|
||||
} catch (err) {}
|
||||
|
||||
const fallback =
|
||||
typeof cacheDirectory !== "string" && directory !== os.tmpdir();
|
||||
|
||||
// Make sure the directory exists.
|
||||
try {
|
||||
await mkdirp(directory);
|
||||
} catch (err) {
|
||||
if (fallback) {
|
||||
return handleCache(os.tmpdir(), params);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Otherwise just transform the file
|
||||
// return it to the user asap and write it in cache
|
||||
const result = await transform(source, options);
|
||||
|
||||
try {
|
||||
await write(file, result);
|
||||
} catch (err) {
|
||||
if (fallback) {
|
||||
// Fallback to tmpdir if node_modules folder not writable
|
||||
return handleCache(os.tmpdir(), params);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve file from cache, or create a new one for future reads
|
||||
*
|
||||
* @async
|
||||
* @param {Object} params
|
||||
* @param {String} params.directory Directory to store cached files
|
||||
* @param {String} params.identifier Unique identifier to bust cache
|
||||
* @param {String} params.source Original contents of the file to be cached
|
||||
* @param {Object} params.options Options to be given to the transform fn
|
||||
* @param {Function} params.transform Function that will transform the
|
||||
* original file and whose result will be
|
||||
* cached
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* cache({
|
||||
* directory: '.tmp/cache',
|
||||
* identifier: 'babel-loader-cachefile',
|
||||
* source: *source code from file*,
|
||||
* options: {
|
||||
* experimental: true,
|
||||
* runtime: true
|
||||
* },
|
||||
* transform: function(source, options) {
|
||||
* var content = *do what you need with the source*
|
||||
* return content;
|
||||
* }
|
||||
* }, function(err, result) {
|
||||
*
|
||||
* });
|
||||
*/
|
||||
|
||||
export default async function cache(params: any) {
|
||||
let directory;
|
||||
|
||||
if (typeof params.cacheDirectory === "string") {
|
||||
directory = params.cacheDirectory;
|
||||
} else {
|
||||
directory = defaultCacheDirectory;
|
||||
}
|
||||
|
||||
return await handleCache(directory, params);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
import LoaderError from './Error'
|
||||
import * as babel from '@babel/core'
|
||||
|
||||
export default async function transform(source: string, options: any) {
|
||||
let result;
|
||||
try {
|
||||
result = await babel.transformAsync(source, options);
|
||||
} catch (err) {
|
||||
throw err.message && err.codeFrame ? new LoaderError(err) : err;
|
||||
}
|
||||
|
||||
if (!result) return null;
|
||||
|
||||
// We don't return the full result here because some entries are not
|
||||
// really serializable. For a full list of properties see here:
|
||||
// https://github.com/babel/babel/blob/master/packages/babel-core/src/transformation/index.js
|
||||
// For discussion on this topic see here:
|
||||
// https://github.com/babel/babel-loader/pull/629
|
||||
const { ast, code, map, metadata } = result;
|
||||
|
||||
if (map && (!map.sourcesContent || !map.sourcesContent.length)) {
|
||||
map.sourcesContent = [source];
|
||||
}
|
||||
|
||||
return { ast, code, map, metadata };
|
||||
};
|
||||
|
||||
export const version = babel.version;
|
|
@ -1 +0,0 @@
|
|||
module.exports = (source) => source
|
4
packages/next/build/webpack/loaders/noop-loader.ts
Normal file
4
packages/next/build/webpack/loaders/noop-loader.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { loader } from 'webpack'
|
||||
|
||||
const NoopLoader: loader.Loader = (source) => source
|
||||
export default NoopLoader
|
|
@ -70,7 +70,6 @@
|
|||
"async-sema": "2.2.0",
|
||||
"autodll-webpack-plugin": "0.4.2",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-loader": "8.0.2",
|
||||
"babel-plugin-react-require": "3.0.0",
|
||||
"babel-plugin-transform-async-to-promises": "0.8.9",
|
||||
"babel-plugin-transform-react-remove-prop-types": "0.4.15",
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2553,16 +2553,6 @@ babel-jest@23.6.0, babel-jest@^23.6.0:
|
|||
babel-plugin-istanbul "^4.1.6"
|
||||
babel-preset-jest "^23.2.0"
|
||||
|
||||
babel-loader@8.0.2:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.2.tgz#2079b8ec1628284a929241da3d90f5b3de2a5ae5"
|
||||
integrity sha512-Law0PGtRV1JL8Y9Wpzc0d6EE0GD7LzXWCfaeWwboUMcBWNG6gvaWTK1/+BK7a4X5EmeJiGEuDDFxUsOa8RSWCw==
|
||||
dependencies:
|
||||
find-cache-dir "^1.0.0"
|
||||
loader-utils "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
util.promisify "^1.0.0"
|
||||
|
||||
babel-messages@^6.23.0:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
|
||||
|
|
Loading…
Reference in a new issue