Skip to content

Commit

Permalink
feat: resolve hook support moduleType to make valid cjs/esm interop
Browse files Browse the repository at this point in the history
  • Loading branch information
ArrayZoneYour committed May 4, 2023
1 parent 40418a1 commit e918c2f
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 16 deletions.
5 changes: 5 additions & 0 deletions cmd/esbuild/service.go
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/evanw/esbuild/internal/config"
"github.com/evanw/esbuild/internal/fs"
"github.com/evanw/esbuild/internal/helpers"
"github.com/evanw/esbuild/internal/js_ast"
"github.com/evanw/esbuild/internal/logger"
"github.com/evanw/esbuild/pkg/api"
"github.com/evanw/esbuild/pkg/cli"
Expand Down Expand Up @@ -920,6 +921,7 @@ func (service *serviceType) convertPlugins(key int, jsPlugins interface{}, activ
"errors": encodeMessages(result.Errors),
"warnings": encodeMessages(result.Warnings),
"path": result.Path,
"moduleType": result.ModuleType,
"external": result.External,
"sideEffects": result.SideEffects,
"namespace": result.Namespace,
Expand Down Expand Up @@ -996,6 +998,9 @@ func (service *serviceType) convertPlugins(key int, jsPlugins interface{}, activ
if value, ok := response["path"]; ok {
result.Path = value.(string)
}
if value, ok := response["moduleType"]; ok {
result.ModuleType = js_ast.ModuleType(value.(int))
}
if value, ok := response["namespace"]; ok {
result.Namespace = value.(string)
}
Expand Down
5 changes: 5 additions & 0 deletions internal/bundler/bundler.go
Expand Up @@ -861,6 +861,11 @@ func RunOnResolvePlugins(
IsExternal: result.External,
PluginData: result.PluginData,
PrimarySideEffectsData: sideEffectsData,
ModuleTypeData: js_ast.ModuleTypeData{
Source: &logger.Source{},
Range: logger.Range{},
Type: result.ModuleType,
},
}, false, resolver.DebugMeta{}
}
}
Expand Down
39 changes: 39 additions & 0 deletions internal/bundler_tests/bundler_importstar_ts_test.go
Expand Up @@ -50,6 +50,45 @@ func TestExcludeExportsForEntryPoint(t *testing.T) {
})
}

func TestExcludeExportsForEntryPointWithTwoClasses(t *testing.T) {
importstar_ts_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.tsx": `
class Test extends Component {
render(){
return <block>
<text>test1</text>
<text>test2</text>
</block>
}
}
export default class Fake extends Component {
state = {
color: 'red',
flag: false
}
render() {
return (
<block>
<text>test</text>
<Test />
</block>
);
}
}
`,
},
entryPaths: []string{"/entry.tsx"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
ExcludeExportForEntry: true,
OutputFormat: config.FormatCommonJS,
},
})
}

func TestCommonClassExport(t *testing.T) {
importstar_ts_suite.expectBundled(t, bundled{
files: map[string]string{
Expand Down
58 changes: 42 additions & 16 deletions internal/bundler_tests/snapshots/snapshots_importstar_ts.txt
Expand Up @@ -15,14 +15,16 @@ var A = class extends Component {
this.renderXXX = () => /* @__PURE__ */ React.createElement("view", null, /* @__PURE__ */ React.createElement("text", null, "asdasdasdasdasdasd"));
}
render() {
return /* @__PURE__ */ React.createElement("view", {
style: { display: "flex", flexDirection: "column" }
}, /* @__PURE__ */ React.createElement("view", {
style: { width: "100rpx", height: "100rpx", backgroundColor: "red" },
bindtap: () => {
this.setState((preState) => ({ count: preState.count + 1 }));
}
}, /* @__PURE__ */ React.createElement("text", null, "Plus 1")), /* @__PURE__ */ React.createElement("text", null, this.state.count), this.renderXXX());
return /* @__PURE__ */ React.createElement("view", { style: { display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(
"view",
{
style: { width: "100rpx", height: "100rpx", backgroundColor: "red" },
bindtap: () => {
this.setState((preState) => ({ count: preState.count + 1 }));
}
},
/* @__PURE__ */ React.createElement("text", null, "Plus 1")
), /* @__PURE__ */ React.createElement("text", null, this.state.count), this.renderXXX());
}
};

Expand All @@ -39,14 +41,38 @@ var A = class extends Component {
this.renderXXX = () => /* @__PURE__ */ React.createElement("view", null, /* @__PURE__ */ React.createElement("text", null, "asdasdasdasdasdasd"));
}
render() {
return /* @__PURE__ */ React.createElement("view", {
style: { display: "flex", flexDirection: "column" }
}, /* @__PURE__ */ React.createElement("view", {
style: { width: "100rpx", height: "100rpx", backgroundColor: "red" },
bindtap: () => {
this.setState((preState) => ({ count: preState.count + 1 }));
}
}, /* @__PURE__ */ React.createElement("text", null, "Plus 1")), /* @__PURE__ */ React.createElement("text", null, this.state.count), this.renderXXX());
return /* @__PURE__ */ React.createElement("view", { style: { display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(
"view",
{
style: { width: "100rpx", height: "100rpx", backgroundColor: "red" },
bindtap: () => {
this.setState((preState) => ({ count: preState.count + 1 }));
}
},
/* @__PURE__ */ React.createElement("text", null, "Plus 1")
), /* @__PURE__ */ React.createElement("text", null, this.state.count), this.renderXXX());
}
};

================================================================================
TestExcludeExportsForEntryPointWithTwoClasses
---------- /out.js ----------
// entry.tsx
var Test = class extends Component {
render() {
return /* @__PURE__ */ React.createElement("block", null, /* @__PURE__ */ React.createElement("text", null, "test1"), /* @__PURE__ */ React.createElement("text", null, "test2"));
}
};
var Fake = class extends Component {
constructor() {
super(...arguments);
this.state = {
color: "red",
flag: false
};
}
render() {
return /* @__PURE__ */ React.createElement("block", null, /* @__PURE__ */ React.createElement("text", null, "test"), /* @__PURE__ */ React.createElement(Test, null));
}
};

Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Expand Up @@ -673,6 +673,7 @@ type OnResolveResult struct {

PluginData interface{}
Path logger.Path
ModuleType js_ast.ModuleType
External bool
IsSideEffectFree bool
}
Expand Down
1 change: 1 addition & 0 deletions lib/shared/common.ts
Expand Up @@ -1259,6 +1259,7 @@ let handlePlugins = async (
errors: replaceDetailsInMessages(response!.errors, details),
warnings: replaceDetailsInMessages(response!.warnings, details),
path: response!.path,
moduleType: response!.moduleType,
external: response!.external,
sideEffects: response!.sideEffects,
namespace: response!.namespace,
Expand Down
2 changes: 2 additions & 0 deletions lib/shared/stdio_protocol.ts
Expand Up @@ -175,6 +175,7 @@ export interface ResolveResponse {
warnings: types.Message[]

path: string
moduleType: number;
external: boolean
sideEffects: boolean
namespace: string
Expand Down Expand Up @@ -202,6 +203,7 @@ export interface OnResolveResponse {
warnings?: types.PartialMessage[]

path?: string
moduleType?: number;
external?: boolean
sideEffects?: boolean
namespace?: string
Expand Down
2 changes: 2 additions & 0 deletions lib/shared/types.ts
Expand Up @@ -333,6 +333,7 @@ export interface ResolveResult {
warnings: Message[]

path: string
moduleType: number;
external: boolean
sideEffects: boolean
namespace: string
Expand Down Expand Up @@ -387,6 +388,7 @@ export interface OnResolveResult {
warnings?: PartialMessage[]

path?: string
moduleType?: number;
external?: boolean
sideEffects?: boolean
namespace?: string
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/api.go
Expand Up @@ -79,6 +79,7 @@ package api
import (
"time"

"github.com/evanw/esbuild/internal/js_ast"
"github.com/evanw/esbuild/internal/logger"
)

Expand Down Expand Up @@ -578,6 +579,7 @@ type ResolveResult struct {
Warnings []Message

Path string
ModuleType int
External bool
SideEffects bool
Namespace string
Expand Down Expand Up @@ -619,6 +621,7 @@ type OnResolveResult struct {
Warnings []Message

Path string
ModuleType js_ast.ModuleType
External bool
SideEffects SideEffects
Namespace string
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/api_impl.go
Expand Up @@ -1952,6 +1952,7 @@ func (impl *pluginImpl) onResolve(options OnResolveOptions, callback func(OnReso
Namespace: response.Namespace,
IgnoredSuffix: response.Suffix,
}
result.ModuleType = response.ModuleType
result.External = response.External
result.IsSideEffectFree = response.SideEffects == SideEffectsFalse
result.PluginData = response.PluginData
Expand Down Expand Up @@ -2093,6 +2094,7 @@ func loadPlugins(initialOptions *BuildOptions, fs fs.FS, log logger.Log, caches
result.Warnings = convertMessagesToPublic(logger.Warning, msgs)
if resolveResult != nil {
result.Path = resolveResult.PathPair.Primary.Text
result.ModuleType = int(resolveResult.ModuleTypeData.Type)
result.External = resolveResult.IsExternal
result.SideEffects = resolveResult.PrimarySideEffectsData == nil
result.Namespace = resolveResult.PathPair.Primary.Namespace
Expand Down
91 changes: 91 additions & 0 deletions test-site/build/interop.ts
@@ -0,0 +1,91 @@
const esbuild = require("../../scripts/esbuild").installForTests();

const createResolver = (options) => {
const { create } = require("enhanced-resolve");
const resolveCache = new Map();
const resolveSync = create.sync({
aliasFields: ["browser"],
conditionNames: ["import", "require", "node"],
mainFields: options.mainFields,
mainFiles: options.mainFiles,
extensions: options.extensions,
preferRelative: options.preferRelative,
addMatchAll: false,
alias: options.alias,
plugins: [],
});
const node_resolve = (id, dir) => {
if (resolveCache.get(id + dir)) {
return resolveCache.get(id + dir);
}
let result;
try {
result = resolveSync({}, dir, id);
} catch (err) {
// hack, scss、less 需要支持~xxx/yyy从npm加载
if (id.endsWith("scss") || id.endsWith("less")) {
result = resolveSync({}, dir, id.replace(/^~/, ""));
} else {
throw err;
}
}
resolveCache.set(id + dir, result);
return result;
};
return node_resolve;
};

const resolver = createResolver({
mainFields: ["lynx", "module", "main"],
mainFiles: ["index.lynx", "index"],
alias: {},
extensions: [
".jsx",
".tsx",
".js",
".ts",
".css",
".less",
".sass",
".scss",
".json",
],
preferRelative: false,
});

const AdapterPlugin = () => {
return {
name: "esbuild:adapter",
setup(build) {
build.onResolve({ filter: /.*/ }, async (args) => {
console.log("onResolve: ", args);
console.log("moduleType: ", args.path.includes("tslib") ? 6 : 0);
return {
// moduleType: args.path.includes("tslib") ? 6 : 0,
moduleType: args.path === "tslib" ? 6 : 0,
// external: args.path === "tslib",
path: resolver(args.path, args.resolveDir),
cacheDisable: true,
};
});
},
};
};

async function exec() {
// interop test
await esbuild.build({
entryPoints: ["src/interop.ts"],
outdir: "dist",
platform: "neutral",
bundle: true,
watch: false,
plugins: [AdapterPlugin()],
format: "cjs",
target: "es2019",
tsconfig: require.resolve("../tsconfig.json"),
external: ["tslib"],
});
}

exec();
2 changes: 2 additions & 0 deletions test-site/src/interop.ts
@@ -0,0 +1,2 @@
import { __assign } from "tslib";
console.log(__assign);

0 comments on commit e918c2f

Please sign in to comment.