@@ -32,6 +32,7 @@ import org.scalajs.linker.interface._
32
32
import org .scalajs .linker .interface .unstable .{IRFileImpl , OutputFileImpl }
33
33
import org .scalajs .linker .backend ._
34
34
import org .scalajs .linker .backend .emitter .Emitter
35
+ import org .scalajs .linker .backend .javascript .{Trees => js }
35
36
import org .scalajs .linker .standard ._
36
37
37
38
/** The Closure backend of the Scala.js linker.
@@ -61,57 +62,68 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
61
62
62
63
override def injectedIRFiles : Seq [IRFile ] = emitter.injectedIRFiles
63
64
64
- private val needsIIFEWrapper = moduleKind match {
65
- case ModuleKind .NoModule => true
66
- case ModuleKind .ESModule | ModuleKind .CommonJSModule => false
67
- }
68
-
69
65
/** Emit the given [[standard.LinkingUnit LinkingUnit ]] to the target output.
70
66
*
71
67
* @param unit [[standard.LinkingUnit LinkingUnit ]] to emit
72
68
* @param output File to write to
73
69
*/
74
70
def emit (unit : LinkingUnit , output : LinkerOutput , logger : Logger )(
75
71
implicit ec : ExecutionContext ): Future [Unit ] = {
76
- Future (compile( unit, output, logger)).flatMap { case (topLevelVarDeclarations, code, sourceMap) =>
77
- logger.timeFuture( " Closure: Write result " ) {
78
- writeResult(topLevelVarDeclarations, code, sourceMap, output)
79
- }
72
+ verifyUnit( unit)
73
+
74
+ val emitterResult = logger.time( " Emitter " ) {
75
+ emitter.emit(unit, logger)
80
76
}
81
- }
82
77
83
- private def compile (unit : LinkingUnit , output : LinkerOutput , logger : Logger ) = {
84
- verifyUnit(unit)
78
+ val module = logger.time(" Closure: Create trees)" ) {
79
+ buildModule(emitterResult.body)
80
+ }
85
81
86
- // Build Closure IR
87
- val (topLevelVarDeclarations, globalRefs, module) = {
88
- logger.time(" Closure: Emitter (create Closure trees)" ) {
89
- val builder = new ClosureModuleBuilder (config.relativizeSourceMapBase)
90
- val (topLevelVarDeclarations, globalRefs) =
91
- emitter.emitForClosure(unit, builder, logger)
92
- (topLevelVarDeclarations, globalRefs, builder.result())
93
- }
82
+ val (code, sourceMap) = logger.time(" Closure: Compiler pass" ) {
83
+ val options = closureOptions(output)
84
+
85
+ val externs = java.util.Arrays .asList(
86
+ ClosureSource .fromCode(" ScalaJSExterns.js" ,
87
+ ClosureLinkerBackend .ScalaJSExterns ),
88
+ ClosureSource .fromCode(" ScalaJSGlobalRefs.js" ,
89
+ makeExternsForGlobalRefs(emitterResult.globalRefs)),
90
+ ClosureSource .fromCode(" ScalaJSExportExterns.js" ,
91
+ makeExternsForExports(emitterResult.topLevelVarDecls, unit)))
92
+
93
+ compile(externs, module, options, logger)
94
94
}
95
95
96
- // Compile the module
97
- val closureExterns = java.util.Arrays .asList(
98
- ClosureSource .fromCode(" ScalaJSExterns.js" , ClosureLinkerBackend .ScalaJSExterns ),
99
- ClosureSource .fromCode(" ScalaJSGlobalRefs.js" , makeExternsForGlobalRefs(globalRefs)),
100
- ClosureSource .fromCode(" ScalaJSExportExterns.js" , makeExternsForExports(topLevelVarDeclarations, unit)))
101
- val options = closureOptions(output)
102
- val compiler = closureCompiler(logger)
103
-
104
- val result = logger.time(" Closure: Compiler pass" ) {
105
- compiler.compileModules(
106
- closureExterns, java.util.Arrays .asList(module), options)
96
+ logger.timeFuture(" Closure: Write result" ) {
97
+ writeResult(emitterResult.header, code, emitterResult.footer, sourceMap, output)
107
98
}
99
+ }
100
+
101
+ private def buildModule (trees : List [js.Tree ]): JSModule = {
102
+ val root = ClosureAstTransformer .transformScript(
103
+ trees, config.relativizeSourceMapBase)
104
+
105
+ val module = new JSModule (" Scala.js" )
106
+ module.add(new CompilerInput (new SyntheticAst (root)))
107
+ module
108
+ }
109
+
110
+ private def compile (externs : java.util.List [ClosureSource ], module : JSModule ,
111
+ options : ClosureOptions , logger : Logger ) = {
112
+ import com .google .common .collect .ImmutableSet
113
+
114
+ val compiler = new ClosureCompiler
115
+ compiler.setErrorManager(new SortingErrorManager (ImmutableSet .of(
116
+ new LoggerErrorReportGenerator (logger))))
117
+
118
+ val result = compiler.compileModules(externs,
119
+ java.util.Arrays .asList(module), options)
108
120
109
121
if (! result.success) {
110
122
throw new LinkingException (
111
123
" There were errors when applying the Google Closure Compiler" )
112
124
}
113
125
114
- (topLevelVarDeclarations, compiler.toSource + " \n " , Option (compiler.getSourceMap()))
126
+ (compiler.toSource + " \n " , Option (compiler.getSourceMap()))
115
127
}
116
128
117
129
/** Constructs an externs file listing all the global refs.
@@ -153,32 +165,9 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
153
165
content.toString()
154
166
}
155
167
156
- private def closureCompiler (logger : Logger ) = {
157
- import com .google .common .collect .ImmutableSet
158
-
159
- val compiler = new ClosureCompiler
160
- compiler.setErrorManager(new SortingErrorManager (ImmutableSet .of(
161
- new LoggerErrorReportGenerator (logger))))
162
- compiler
163
- }
164
-
165
- private def writeResult (topLevelVarDeclarations : List [String ],
166
- outputContent : String , sourceMap : Option [SourceMap ], output : LinkerOutput )(
168
+ private def writeResult (header : String , body : String , footer : String ,
169
+ sourceMap : Option [SourceMap ], output : LinkerOutput )(
167
170
implicit ec : ExecutionContext ): Future [Unit ] = {
168
-
169
- def ifIIFE (str : String ): String = if (needsIIFEWrapper) str else " "
170
-
171
- val header = {
172
- val maybeTopLevelVarDecls = if (topLevelVarDeclarations.nonEmpty) {
173
- val kw = if (esFeatures.useECMAScript2015) " let " else " var "
174
- topLevelVarDeclarations.mkString(kw, " ," , " ;\n " )
175
- } else {
176
- " "
177
- }
178
- maybeTopLevelVarDecls + ifIIFE(" (function(){" ) + " 'use strict';\n "
179
- }
180
- val footer = ifIIFE(" }).call(this);\n " )
181
-
182
171
def writeToFile (file : LinkerOutput .File )(content : Writer => Unit ): Future [Unit ] = {
183
172
val out = new ByteArrayOutputStream ()
184
173
val writer = new OutputStreamWriter (out, StandardCharsets .UTF_8 )
@@ -192,7 +181,7 @@ final class ClosureLinkerBackend(config: LinkerBackendImpl.Config)
192
181
// Write optimized code
193
182
val codeWritten = writeToFile(output.jsFile) { w =>
194
183
w.write(header)
195
- w.write(outputContent )
184
+ w.write(body )
196
185
w.write(footer)
197
186
output.sourceMapURI.foreach(uri =>
198
187
w.write(" //# sourceMappingURL=" + uri.toASCIIString + " \n " ))
0 commit comments