Skip to content
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@google-cloud/firestore": "^4.14.0",
"@sentry/node": "^6.10.0",
"@slack/web-api": "^6.3.0",
"@swc/wasm": "^1.2.89",
"@tensorflow/tfjs-node": "^3.8.0",
"@vercel/webpack-asset-relocator-loader": "1.6.0",
"analytics-node": "^5.0.0",
Expand Down Expand Up @@ -63,6 +64,7 @@
"isomorphic-unfetch": "^3.0.0",
"jest": "^27.0.6",
"jimp": "^0.16.1",
"json5": "^2.2.0",
"jugglingdb": "2.0.1",
"koa": "^2.6.2",
"leveldown": "^6.0.0",
Expand All @@ -72,6 +74,7 @@
"mailgun": "^0.5.0",
"mariadb": "^2.0.1-beta",
"memcached": "^2.2.2",
"memory-fs": "^0.5.0",
"mkdirp": "^1.0.4",
"mongoose": "^5.3.12",
"mysql": "^2.16.0",
Expand All @@ -97,15 +100,13 @@
"socket.io": "^4.1.3",
"source-map-support": "^0.5.9",
"stripe": "^8.167.0",
"swc-loader": "^0.1.15",
"swig": "^1.4.2",
"terser": "^5.6.1",
"the-answer": "^1.0.0",
"tiny-json-http": "^7.0.2",
"ts-loader": "^8.3.0",
"tsconfig-paths": "^3.7.0",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"twilio": "^3.23.2",
"typescript": "^4.4.2",
"typescript": "^4.4.3",
"vm2": "^3.6.6",
"vue": "^2.5.17",
"vue-server-renderer": "^2.5.17",
Expand Down
17 changes: 9 additions & 8 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,23 @@ async function main() {
);
checkUnknownAssets('shebang-loader', Object.keys(shebangLoaderAssets));

const { code: tsLoader, assets: tsLoaderAssets } = await ncc(
__dirname + "/../src/loaders/ts-loader",
const { code: swcLoader, assets: swcLoaderAssets } = await ncc(
__dirname + "/../src/loaders/swc-loader",
{
filename: "ts-loader.js",
filename: "swc-loader.js",
minify,
cache,
v8cache,
noAssetBuilds: true
},
);
checkUnknownAssets('ts-loader', Object.keys(tsLoaderAssets).filter(asset => !asset.startsWith('lib/') && !asset.startsWith('typescript/lib')));
checkUnknownAssets('swc-loader', Object.keys(swcLoaderAssets).filter(asset => asset !== 'wasm_bg.wasm'));

const { code: stringifyLoader, assets: stringifyLoaderAssets } = await ncc(
__dirname + "/../src/loaders/stringify-loader",
{ filename: "stringify-loader.js", minify, cache, v8cache }
);
checkUnknownAssets('stringify-loader', Object.keys(stringifyLoader));
checkUnknownAssets('stringify-loader', Object.keys(stringifyLoaderAssets));

const { code: sourcemapSupport, assets: sourcemapAssets } = await ncc(
require.resolve("source-map-support/register"),
Expand All @@ -92,15 +92,16 @@ async function main() {
writeFileSync(__dirname + "/../dist/ncc/sourcemap-register.js.cache", sourcemapAssets["sourcemap-register.js.cache"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/relocate-loader.js.cache", relocateLoaderAssets["relocate-loader.js.cache"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/shebang-loader.js.cache", shebangLoaderAssets["shebang-loader.js.cache"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/ts-loader.js.cache", tsLoaderAssets["ts-loader.js.cache"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/swc-loader.js.cache", swcLoaderAssets["swc-loader.js.cache"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/wasm_bg.wasm", swcLoaderAssets["wasm_bg.wasm"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/stringify-loader.js.cache", stringifyLoaderAssets["stringify-loader.js.cache"].source);

writeFileSync(__dirname + "/../dist/ncc/cli.js.cache.js", cliAssets["cli.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/index.js.cache.js", indexAssets["index.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/sourcemap-register.js.cache.js", sourcemapAssets["sourcemap-register.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/relocate-loader.js.cache.js", relocateLoaderAssets["relocate-loader.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/shebang-loader.js.cache.js", shebangLoaderAssets["shebang-loader.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/ts-loader.js.cache.js", tsLoaderAssets["ts-loader.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/swc-loader.js.cache.js", swcLoaderAssets["swc-loader.js.cache.js"].source);
writeFileSync(__dirname + "/../dist/ncc/loaders/stringify-loader.js.cache.js", stringifyLoaderAssets["stringify-loader.js.cache.js"].source);

writeFileSync(__dirname + "/../dist/ncc/cli.js", cli, { mode: 0o777 });
Expand All @@ -109,7 +110,7 @@ async function main() {
writeFileSync(__dirname + "/../dist/ncc/sourcemap-register.js", sourcemapSupport);
writeFileSync(__dirname + "/../dist/ncc/loaders/relocate-loader.js", relocateLoader);
writeFileSync(__dirname + "/../dist/ncc/loaders/shebang-loader.js", shebangLoader);
writeFileSync(__dirname + "/../dist/ncc/loaders/ts-loader.js", tsLoader);
writeFileSync(__dirname + "/../dist/ncc/loaders/swc-loader.js", swcLoader);
writeFileSync(__dirname + "/../dist/ncc/loaders/stringify-loader.js", stringifyLoader);
writeFileSync(__dirname + "/../dist/ncc/loaders/uncacheable.js", readFileSync(__dirname + "/../src/loaders/uncacheable.js"));
writeFileSync(__dirname + "/../dist/ncc/loaders/empty-loader.js", readFileSync(__dirname + "/../src/loaders/empty-loader.js"));
Expand Down
78 changes: 41 additions & 37 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ const { join, dirname, extname, relative, resolve: pathResolve } = require("path
const webpack = require("webpack");
const MemoryFS = require("memory-fs");
const terser = require("terser");
const tsconfigPaths = require("tsconfig-paths");
const { loadTsconfig } = require("tsconfig-paths/lib/tsconfig-loader");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const JSON5 = require("json5");
const shebangRegEx = require('./utils/shebang');
const nccCacheDir = require("./utils/ncc-cache-dir");
const LicenseWebpackPlugin = require('license-webpack-plugin').LicenseWebpackPlugin;
const { LicenseWebpackPlugin } = require('license-webpack-plugin');
const { version: nccVersion } = require('../package.json');
const { hasTypeModule } = require('./utils/has-type-module');

Expand Down Expand Up @@ -105,31 +103,23 @@ function ncc (
existingAssetNames.push(`${filename}.cache`);
existingAssetNames.push(`${filename}.cache${ext}`);
}
const resolvePlugins = [];
// add TsconfigPathsPlugin to support `paths` resolution in tsconfig
// we need to catch here because the plugin will
// error if there's no tsconfig in the working directory
let fullTsconfig = {};

let tsconfig = {};
try {
const configFileAbsolutePath = walkParentDirs({
const configPath = walkParentDirs({
base: process.cwd(),
start: dirname(entry),
filename: 'tsconfig.json',
});
fullTsconfig = loadTsconfig(configFileAbsolutePath) || {
compilerOptions: {}
};

const tsconfigPathsOptions = { silent: true }
if (fullTsconfig.compilerOptions.allowJs) {
tsconfigPathsOptions.extensions = SUPPORTED_EXTENSIONS
}
resolvePlugins.push(new TsconfigPathsPlugin(tsconfigPathsOptions));

if (tsconfig.resultType === "success") {
tsconfigMatchPath = tsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths);
}
const contents = fs.readFileSync(configPath, 'utf8')
tsconfig = JSON5.parse(contents);
const baseUrl = tsconfig.compilerOptions.baseUrl;
resolveModules.push(pathResolve(dirname(configPath), baseUrl));
} catch (e) {}
const resolvePlugins = [];
const resolveModules = [];
const compilerOptions = tsconfig.compilerOptions || {};


resolvePlugins.push({
apply(resolver) {
Expand Down Expand Up @@ -294,6 +284,7 @@ function ncc (
// webpack defaults to `module` and `main`, but that's
// not really what node.js supports, so we reset it
mainFields: ["main"],
modules: resolveModules.length > 0 ? resolveModules : undefined,
plugins: resolvePlugins
},
// https://github.com/vercel/ncc/pull/29#pullrequestreview-177152175
Expand Down Expand Up @@ -333,17 +324,30 @@ function ncc (
loader: eval('__dirname + "/loaders/uncacheable.js"')
},
{
loader: eval('__dirname + "/loaders/ts-loader.js"'),
loader: eval('__dirname + "/loaders/swc-loader.js"'),
options: {
transpileOnly,
compiler: eval('__dirname + "/typescript.js"'),
compilerOptions: {
module: 'esnext',
target: 'esnext',
...fullTsconfig.compilerOptions,
allowSyntheticDefaultImports: true,
noEmit: false,
outDir: '//'
minify: false, // TODO: maybe we could omit terser if `true`?
exclude: tsconfig.exclude,
sourceMaps: compilerOptions.sourceMap || false,
module: {
type: compilerOptions.module && compilerOptions.module.toLowerCase() === 'commonjs' ? 'commonjs' : 'es6',
strict: false,
strictMode: true,
lazy: false,
noInterop: !compilerOptions.esModuleInterop
},
jsc: {
externalHelpers: false,
keepClassNames: true,
target: compilerOptions.target && compilerOptions.target.toLowerCase() || 'es2021',
paths: compilerOptions.paths,
baseUrl: compilerOptions.baseUrl,
Copy link
Member Author

@styfle styfle Sep 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kdy1 The paths and baseUrl tests are failing with:

panicked at 'failed to get current directory: Error { kind: Unsupported, message: "operation not supported on this platform" }', /home/runner/work/swc/swc/ecmascript/transforms/module/src/path.rs:81:56

Stack:

Error: 
    at u.exports.__wbg_new_59cb74e423758ede (dist/ncc/loaders/swc-loader.js.cache.js:1:2692)
    at null.<anonymous> (wasm://wasm/04480186:0:15193164)
    at null.<anonymous> (wasm://wasm/04480186:0:16752724)
    at null.<anonymous> (wasm://wasm/04480186:0:16566604)
    at null.<anonymous> (wasm://wasm/04480186:0:16677644)
    at null.<anonymous> (wasm://wasm/04480186:0:16749249)
    at null.<anonymous> (wasm://wasm/04480186:0:16736138)
    at null.<anonymous> (wasm://wasm/04480186:0:16687572)
    at null.<anonymous> (wasm://wasm/04480186:0:5322716)
    at null.<anonymous> (wasm://wasm/04480186:0:15233495)

Copy link
Member Author

@styfle styfle Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kdy1 The new @swc/wasm no longer panics, but it still fails with very strange behavior.

Input:

https://github.com/vercel/ncc/blob/main/test/unit/tsconfig-paths/input.ts

import module from "@module";

console.log(module);

Output:

/******/ 	var __webpack_modules__ = ({

/***/ 105:
/***/ ((module) => {

module.exports = eval("require")("../../../../../../../../.././module");


/***/ })

/******/ 	});

Runtime result:

Error: Cannot find module '../../../../../../../../.././module'

parser: {
syntax: 'typescript',
tsx: true, // TODO: use tsconfig.compilerOptions.jsx ???
decorators: compilerOptions.experimentalDecorators || false,
dynamicImport: true, // TODO: use module ???
}
}
}
}]
Expand Down Expand Up @@ -431,7 +435,7 @@ function ncc (

async function finalizeHandler (stats) {
const assets = Object.create(null);
getFlatFiles(mfs.data, assets, relocateLoader.getAssetMeta, fullTsconfig);
getFlatFiles(mfs.data, assets, relocateLoader.getAssetMeta, compilerOptions);
// filter symlinks to existing assets
const symlinks = Object.create(null);
for (const [key, value] of Object.entries(relocateLoader.getSymlinks())) {
Expand Down Expand Up @@ -625,17 +629,17 @@ function ncc (
}

// this could be rewritten with actual FS apis / globs, but this is simpler
function getFlatFiles(mfsData, output, getAssetMeta, tsconfig, curBase = "") {
function getFlatFiles(mfsData, output, getAssetMeta, compilerOptions, curBase = "") {
for (const path of Object.keys(mfsData)) {
const item = mfsData[path];
let curPath = `${curBase}/${path}`;
// directory
if (item[""] === true) getFlatFiles(item, output, getAssetMeta, tsconfig, curPath);
if (item[""] === true) getFlatFiles(item, output, getAssetMeta, compilerOptions, curPath);
// file
else if (!curPath.endsWith("/")) {
const meta = getAssetMeta(curPath.substr(1)) || {};
if(curPath.endsWith(".d.ts")) {
const outDir = tsconfig.compilerOptions.outDir ? pathResolve(tsconfig.compilerOptions.outDir) : pathResolve('dist');
const outDir = compilerOptions.outDir ? pathResolve(compilerOptions.outDir) : pathResolve('dist');
curPath = curPath
.replace(outDir, "")
.replace(process.cwd(), "")
Expand Down
94 changes: 94 additions & 0 deletions src/loaders/swc-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Source code from https://github.com/swc-project/swc-loader/blob/master/src/index.js
// with the following changes:
// - swapped out `@swc/core` for `@swc/wasm`
// - swapped out `swc.transform()` for `swc.transformSync()`

const loaderUtils = require("loader-utils");
const swc = require("@swc/wasm");

function makeLoader() {
return function (source, inputSourceMap) {
// Make the loader async
const callback = this.async();
const filename = this.resourcePath;

let loaderOptions = loaderUtils.getOptions(this) || {};

// 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;
}

if (inputSourceMap) {
inputSourceMap = JSON.stringify(inputSourceMap);
}

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,
});
if (!programmaticOptions.inputSourceMap) {
delete programmaticOptions.inputSourceMap;
}

const parseMap = programmaticOptions.parseMap;

delete programmaticOptions.parseMap;
delete programmaticOptions.customize;
delete programmaticOptions.cacheDirectory;
delete programmaticOptions.cacheIdentifier;
delete programmaticOptions.cacheCompression;
delete programmaticOptions.metadataSubscribers;

// auto detect development mode
if (this.mode && programmaticOptions.jsc && programmaticOptions.jsc.transform
&& programmaticOptions.jsc.transform.react &&
!Object.prototype.hasOwnProperty.call(programmaticOptions.jsc.transform.react, "development")) {
programmaticOptions.jsc.transform.react.development = this.mode === 'development'
}

if (programmaticOptions.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'.
programmaticOptions.sourceMaps = true;
}

try {
const output = swc.transformSync(source, programmaticOptions);
callback(
null,
output.code,
parseMap ? JSON.parse(output.map) : output.map
);
} catch (e) {
callback(e);
}
};
}

module.exports = makeLoader();
module.exports.custom = makeLoader;
24 changes: 0 additions & 24 deletions src/loaders/ts-loader.js

This file was deleted.

Loading