next-plugin-preval
Version:
> Pre-evaluate async functions (for data fetches) at build time and import them like JSON
123 lines (119 loc) • 5.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._prevalLoader = _prevalLoader;
exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _requireFromString = _interopRequireDefault(require("require-from-string"));
var _babelPluginModuleResolver = require("babel-plugin-module-resolver");
var _loaderUtils = require("loader-utils");
var _tsconfigPaths = require("tsconfig-paths");
var _isSerializable = _interopRequireDefault(require("./is-serializable"));
var _register = _interopRequireWildcard(require("@babel/register"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
// @ts-expect-error
// @ts-expect-error
class PrevalError extends Error {}
const defaultExtensions = ['.js', '.jsx', '.ts', '.tsx'];
const isRecord = something => typeof something === 'object' && !!something && !Array.isArray(something);
const readJson = filename => {
try {
return require(filename);
} catch {
return undefined;
}
};
const fileExists = filename => {
try {
return _fs.default.existsSync(filename);
} catch {
return false;
}
};
async function _prevalLoader(_, resource, options) {
const {
extensions = defaultExtensions
} = options;
const configLoaderResult = (0, _tsconfigPaths.loadConfig)();
const configLoaderSuccessResult = configLoaderResult.resultType === 'failed' ? null : configLoaderResult;
const matchPath = configLoaderSuccessResult && (0, _tsconfigPaths.createMatchPath)(configLoaderSuccessResult.absoluteBaseUrl, configLoaderSuccessResult.paths);
const moduleResolver = configLoaderSuccessResult && ['module-resolver', {
extensions,
resolvePath: (sourcePath, currentFile, opts) => {
if (matchPath) {
try {
return matchPath(sourcePath, readJson, fileExists, extensions);
} catch {
return (0, _babelPluginModuleResolver.resolvePath)(sourcePath, currentFile, opts);
}
}
return (0, _babelPluginModuleResolver.resolvePath)(sourcePath, currentFile, opts);
}
}];
(0, _register.default)({
// this is used by `next/babel` preset to conditionally remove loaders.
// without it, it causes the dreaded `e.charCodeAt is not a function` error.
// see:
// - https://github.com/ricokahler/next-plugin-preval/issues/66
// - https://github.com/vercel/next.js/blob/37d11008250b3b87dfa4625cd228ac173d4d3563/packages/next/build/babel/preset.ts#L65
caller: {
isServer: true
},
presets: ['next/babel', ['@babel/preset-env', {
targets: 'node 12'
}]],
plugins: [
// conditionally add
...(moduleResolver ? [moduleResolver] : [])],
rootMode: 'upward-optional',
// TODO: this line may cause performance issues, it makes babel compile
// things `node_modules` however this is currently required for setups that
// include the use of sym-linked deps as part of workspaces (both yarn and
// npm)
ignore: [],
// disables the warning "Babel has de-optimized the styling of..."
compact: true,
extensions
});
const data = await (async () => {
try {
const mod = (0, _requireFromString.default)(`require('next');\nmodule.exports = require(${JSON.stringify(resource)})`, `${resource}.preval.js`);
if (!mod.default) {
throw new PrevalError('No default export. Did you forget to `export default`?');
}
return await mod.default;
} catch (e) {
if (isRecord(e) && 'stack' in e) {
// TODO: use the webpack logger. i tried this and it didn't output anything.
console.error('[next-plugin-preval]', e.stack);
}
throw new PrevalError(`Failed to pre-evaluate "${resource}". ${e} See above for full stack trace.`);
} finally {
(0, _register.revert)();
}
})();
(0, _isSerializable.default)(resource, data);
// NOTE we wrap in JSON.parse because that's faster for JS engines to parse
// over javascript. see here https://v8.dev/blog/cost-of-javascript-2019#json
//
// We wrap in JSON.stringify twice. Once for a JSON string and once again for
// a JSON string that can be embeddable in javascript.
return `module.exports = JSON.parse(${JSON.stringify(JSON.stringify(data))})`;
}
const loader = function (content) {
const callback = this.async();
this.cacheable(false);
if (!callback) {
throw new PrevalError('Async was not supported by webpack. Please open an issue in next-plugin-preval.');
}
_prevalLoader(content.toString(), this.resourcePath, (0, _loaderUtils.getOptions)(this)).then(result => {
callback(null, result);
}).catch(e => {
callback(e);
});
};
var _default = exports.default = loader;
//# sourceMappingURL=loader.js.map