Skip to content

Commit 38b4a6a

Browse files
authored
Don't analyze splitting when the sideEffects set to false (#1111)
1 parent 4d64d78 commit 38b4a6a

File tree

2 files changed

+162
-159
lines changed

2 files changed

+162
-159
lines changed

server/build.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,12 @@ func (ctx *BuildContext) Build() (meta *BuildMeta, err error) {
145145
}
146146

147147
// analyze splitting modules
148-
ctx.status = "analyze"
149-
err = ctx.analyzeSplitting()
150-
if err != nil {
151-
return
148+
if !ctx.pkgJson.SideEffectsFalse && ctx.bundleMode == BundleDefault && ctx.pkgJson.Exports.Len() > 1 {
149+
ctx.status = "analyze"
150+
err = ctx.analyzeSplitting()
151+
if err != nil {
152+
return
153+
}
152154
}
153155

154156
// build the module

server/build_analyzer.go

Lines changed: 156 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -18,188 +18,189 @@ type Ref struct {
1818
}
1919

2020
func (ctx *BuildContext) analyzeSplitting() (err error) {
21-
if ctx.bundleMode == BundleDefault && ctx.pkgJson.Exports.Len() > 1 {
22-
exportNames := set.New[string]()
23-
for _, exportName := range ctx.pkgJson.Exports.keys {
24-
exportName := stripEntryModuleExt(exportName)
25-
if (exportName == "." || (strings.HasPrefix(exportName, "./") && !strings.ContainsRune(exportName, '*'))) && !endsWith(exportName, ".json", ".css", ".wasm", ".d.ts", ".d.mts", ".d.cts") {
26-
v := ctx.pkgJson.Exports.values[exportName]
27-
if s, ok := v.(string); ok {
28-
if endsWith(s, ".json", ".css", ".wasm", ".d.ts", ".d.mts", ".d.cts") {
29-
continue
30-
}
31-
} else if obj, ok := v.(JSONObject); ok {
32-
// ignore types only exports
33-
if len(obj.keys) == 1 && obj.keys[0] == "types" {
34-
continue
35-
}
36-
}
37-
if exportName == "." {
38-
exportNames.Add("")
39-
} else if strings.HasPrefix(exportName, "./") {
40-
exportNames.Add(exportName[2:])
21+
exportNames := set.New[string]()
22+
23+
for _, exportName := range ctx.pkgJson.Exports.keys {
24+
exportName := stripEntryModuleExt(exportName)
25+
if (exportName == "." || (strings.HasPrefix(exportName, "./") && !strings.ContainsRune(exportName, '*'))) && !endsWith(exportName, ".json", ".css", ".wasm", ".d.ts", ".d.mts", ".d.cts") {
26+
v := ctx.pkgJson.Exports.values[exportName]
27+
if s, ok := v.(string); ok {
28+
if endsWith(s, ".json", ".css", ".wasm", ".d.ts", ".d.mts", ".d.cts") {
29+
continue
30+
}
31+
} else if obj, ok := v.(JSONObject); ok {
32+
// ignore types only exports
33+
if len(obj.keys) == 1 && obj.keys[0] == "types" {
34+
continue
4135
}
4236
}
37+
if exportName == "." {
38+
exportNames.Add("")
39+
} else if strings.HasPrefix(exportName, "./") {
40+
exportNames.Add(exportName[2:])
41+
}
4342
}
44-
if exportNames.Len() > 1 {
45-
splittingTxtPath := path.Join(ctx.wd, "splitting.txt")
46-
readSplittingTxt := func() bool {
47-
f, err := os.Open(splittingTxtPath)
48-
if err != nil {
49-
return false
50-
}
51-
defer f.Close()
43+
}
44+
45+
if exportNames.Len() > 1 {
46+
splittingTxtPath := path.Join(ctx.wd, "splitting.txt")
47+
readSplittingTxt := func() bool {
48+
f, err := os.Open(splittingTxtPath)
49+
if err != nil {
50+
return false
51+
}
52+
defer f.Close()
5253

53-
var a []string
54-
var i int
55-
var r = bufio.NewReader(f)
56-
for {
57-
line, readErr := r.ReadString('\n')
58-
if readErr == nil || readErr == io.EOF {
59-
line = strings.TrimSpace(line)
60-
if line != "" {
61-
if a == nil {
62-
n, e := strconv.Atoi(line)
63-
if e != nil {
64-
break
65-
}
66-
a = make([]string, n+1)
54+
var a []string
55+
var i int
56+
var r = bufio.NewReader(f)
57+
for {
58+
line, readErr := r.ReadString('\n')
59+
if readErr == nil || readErr == io.EOF {
60+
line = strings.TrimSpace(line)
61+
if line != "" {
62+
if a == nil {
63+
n, e := strconv.Atoi(line)
64+
if e != nil {
65+
break
6766
}
68-
a[i] = line
69-
i++
67+
a = make([]string, n+1)
7068
}
71-
}
72-
if readErr != nil {
73-
break
69+
a[i] = line
70+
i++
7471
}
7572
}
76-
if len(a) > 0 {
77-
n, e := strconv.Atoi(a[0])
78-
if e == nil && n <= len(a)-1 {
79-
ctx.splitting = set.NewReadOnly(a[1 : n+1]...)
80-
if DEBUG {
81-
ctx.logger.Debugf("build(%s): splitting.txt found with %d shared modules", ctx.esm.Specifier(), ctx.splitting.Len())
82-
}
83-
return true
73+
if readErr != nil {
74+
break
75+
}
76+
}
77+
if len(a) > 0 {
78+
n, e := strconv.Atoi(a[0])
79+
if e == nil && n <= len(a)-1 {
80+
ctx.splitting = set.NewReadOnly(a[1 : n+1]...)
81+
if DEBUG {
82+
ctx.logger.Debugf("build(%s): splitting.txt found with %d shared modules", ctx.esm.Specifier(), ctx.splitting.Len())
8483
}
84+
return true
8585
}
86-
return false
8786
}
87+
return false
88+
}
8889

89-
// check if the splitting has been analyzed
90-
if readSplittingTxt() {
91-
return
92-
}
90+
// check if the splitting has been analyzed
91+
if readSplittingTxt() {
92+
return
93+
}
9394

94-
// only one analyze process is allowed at the same time for the same package
95-
unlock := installMutex.Lock(splittingTxtPath)
96-
defer unlock()
95+
// only one analyze process is allowed at the same time for the same package
96+
unlock := installMutex.Lock(splittingTxtPath)
97+
defer unlock()
9798

98-
// skip analyze if the package has been analyzed by another request
99-
if readSplittingTxt() {
100-
return
101-
}
99+
// skip analyze if the package has been analyzed by another request
100+
if readSplittingTxt() {
101+
return
102+
}
102103

103-
defer func() {
104-
splitting := []string{}
105-
if ctx.splitting != nil {
106-
splitting = ctx.splitting.Values()
107-
}
108-
// write the splitting result to 'splitting.txt'
109-
sizeStr := strconv.FormatUint(uint64(len(splitting)), 10)
110-
bufSize := len(sizeStr) + 1
111-
for _, s := range splitting {
112-
bufSize += len(s) + 1
113-
}
114-
buf := make([]byte, bufSize)
115-
i := copy(buf, sizeStr)
104+
defer func() {
105+
splitting := []string{}
106+
if ctx.splitting != nil {
107+
splitting = ctx.splitting.Values()
108+
}
109+
// write the splitting result to 'splitting.txt'
110+
sizeStr := strconv.FormatUint(uint64(len(splitting)), 10)
111+
bufSize := len(sizeStr) + 1
112+
for _, s := range splitting {
113+
bufSize += len(s) + 1
114+
}
115+
buf := make([]byte, bufSize)
116+
i := copy(buf, sizeStr)
117+
buf[i] = '\n'
118+
i++
119+
for _, s := range splitting {
120+
i += copy(buf[i:], s)
116121
buf[i] = '\n'
117122
i++
118-
for _, s := range splitting {
119-
i += copy(buf[i:], s)
120-
buf[i] = '\n'
121-
i++
122-
}
123-
os.WriteFile(splittingTxtPath, buf[0:bufSize-1], 0644)
124-
}()
123+
}
124+
os.WriteFile(splittingTxtPath, buf[0:bufSize-1], 0644)
125+
}()
125126

126-
refs := map[string]Ref{}
127-
for _, exportName := range exportNames.Values() {
128-
esm := ctx.esm
129-
esm.SubPath = exportName
130-
esm.SubModuleName = stripEntryModuleExt(exportName)
131-
b := &BuildContext{
132-
npmrc: ctx.npmrc,
133-
logger: ctx.logger,
134-
db: ctx.db,
135-
storage: ctx.storage,
136-
esm: esm,
137-
args: ctx.args,
138-
externalAll: ctx.externalAll,
139-
target: ctx.target,
140-
dev: ctx.dev,
141-
wd: ctx.wd,
142-
pkgJson: ctx.pkgJson,
143-
}
144-
_, includes, err := b.buildModule(true)
145-
if err != nil {
146-
return fmt.Errorf("failed to analyze %s: %v", esm.Specifier(), err)
147-
}
148-
for _, include := range includes {
149-
module, importer := include[0], include[1]
150-
ref, ok := refs[module]
151-
if !ok {
152-
ref = Ref{entries: set.New[string](), importers: set.New[string]()}
153-
refs[module] = ref
154-
}
155-
ref.importers.Add(importer)
156-
ref.entries.Add(exportName)
157-
}
127+
refs := map[string]Ref{}
128+
for _, exportName := range exportNames.Values() {
129+
esm := ctx.esm
130+
esm.SubPath = exportName
131+
esm.SubModuleName = stripEntryModuleExt(exportName)
132+
b := &BuildContext{
133+
npmrc: ctx.npmrc,
134+
logger: ctx.logger,
135+
db: ctx.db,
136+
storage: ctx.storage,
137+
esm: esm,
138+
args: ctx.args,
139+
externalAll: ctx.externalAll,
140+
target: ctx.target,
141+
dev: ctx.dev,
142+
wd: ctx.wd,
143+
pkgJson: ctx.pkgJson,
158144
}
159-
shared := set.New[string]()
160-
for mod, ref := range refs {
161-
if ref.entries.Len() > 1 && ref.importers.Len() > 1 {
162-
shared.Add(mod)
163-
}
145+
_, includes, err := b.buildModule(true)
146+
if err != nil {
147+
return fmt.Errorf("failed to analyze %s: %v", esm.Specifier(), err)
148+
}
149+
for _, include := range includes {
150+
module, importer := include[0], include[1]
151+
ref, ok := refs[module]
152+
if !ok {
153+
ref = Ref{entries: set.New[string](), importers: set.New[string]()}
154+
refs[module] = ref
155+
}
156+
ref.importers.Add(importer)
157+
ref.entries.Add(exportName)
158+
}
159+
}
160+
shared := set.New[string]()
161+
for mod, ref := range refs {
162+
if ref.entries.Len() > 1 && ref.importers.Len() > 1 {
163+
shared.Add(mod)
164164
}
165-
var bubble func(modulePath string, f func(string), mark *set.Set[string])
166-
bubble = func(modulePath string, f func(string), mark *set.Set[string]) {
167-
hasMark := mark != nil
168-
if !hasMark {
169-
mark = set.New[string]()
170-
} else if mark.Has(modulePath) {
165+
}
166+
var bubble func(modulePath string, f func(string), mark *set.Set[string])
167+
bubble = func(modulePath string, f func(string), mark *set.Set[string]) {
168+
hasMark := mark != nil
169+
if !hasMark {
170+
mark = set.New[string]()
171+
} else if mark.Has(modulePath) {
172+
return
173+
}
174+
mark.Add(modulePath)
175+
ref, ok := refs[modulePath]
176+
if ok {
177+
if shared.Has(modulePath) && hasMark {
178+
f(modulePath)
171179
return
172180
}
173-
mark.Add(modulePath)
174-
ref, ok := refs[modulePath]
175-
if ok {
176-
if shared.Has(modulePath) && hasMark {
177-
f(modulePath)
178-
return
179-
}
180-
for _, importer := range ref.importers.Values() {
181-
bubble(importer, f, mark)
182-
}
183-
} else {
184-
// modulePath is an entry module
185-
f(modulePath)
181+
for _, importer := range ref.importers.Values() {
182+
bubble(importer, f, mark)
186183
}
184+
} else {
185+
// modulePath is an entry module
186+
f(modulePath)
187187
}
188-
if shared.Len() > 0 {
189-
splitting := set.New[string]()
190-
for _, modulePath := range shared.Values() {
191-
refBy := set.New[string]()
192-
bubble(modulePath, func(importer string) { refBy.Add(importer) }, nil)
193-
if refBy.Len() > 1 {
194-
splitting.Add(modulePath)
195-
}
196-
}
197-
ctx.splitting = splitting.ReadOnly()
198-
if DEBUG {
199-
ctx.logger.Debugf("build(%s): found %d shared modules from %d modules", ctx.esm.Specifier(), shared.Len(), len(refs))
188+
}
189+
if shared.Len() > 0 {
190+
splitting := set.New[string]()
191+
for _, modulePath := range shared.Values() {
192+
refBy := set.New[string]()
193+
bubble(modulePath, func(importer string) { refBy.Add(importer) }, nil)
194+
if refBy.Len() > 1 {
195+
splitting.Add(modulePath)
200196
}
201197
}
198+
ctx.splitting = splitting.ReadOnly()
199+
if DEBUG {
200+
ctx.logger.Debugf("build(%s): found %d shared modules from %d modules", ctx.esm.Specifier(), shared.Len(), len(refs))
201+
}
202202
}
203203
}
204+
204205
return
205206
}

0 commit comments

Comments
 (0)