docs: public static Optional<CompiledTemplates> compile(
        final TemplateRegistry registry,
        final SoyFileSetNode fileSet,
        boolean developmentMode,
        ErrorReporter reporter,
        ImmutableMap<String, SoyFileSupplier> filePathsToSuppliers,
        SoyTypeRegistry typeRegistry) {
      final Stopwatch stopwatch = Stopwatch.createStarted();
      ErrorReporter.Checkpoint checkpoint = reporter.checkpoint();
      if (reporter.errorsSince(checkpoint)) {
        return Optional.absent();
      }
      CompiledTemplateRegistry compilerRegistry = new CompiledTemplateRegistry(registry);
      if (developmentMode) {
        CompiledTemplates templates =
            new CompiledTemplates(
                compilerRegistry.getDelegateTemplateNames(),
                new CompilingClassLoader(
                    compilerRegistry, fileSet, filePathsToSuppliers, typeRegistry));
        if (reporter.errorsSince(checkpoint)) {
          return Optional.absent();
        }
        // TODO(lukes): consider spawning a thread to load all the generated classes in the background
        return Optional.of(templates);
      }
      // TODO(lukes): once most internal users have moved to precompilation eliminate this and just
      // use the 'developmentMode' path above.  This hybrid only makes sense for production services
      // that are doing runtime compilation.  Hopefully, this will become an anomaly.
      List<ClassData> classes =
          compileTemplates(
              compilerRegistry,
              fileSet,
              reporter,
              typeRegistry,
              new CompilerListener<List<ClassData>>() {
                final List<ClassData> compiledClasses = new ArrayList<>();
                int numBytes = 0;
                int numFields = 0;
                int numDetachStates = 0;
  
                @Override
                public void onCompile(ClassData clazz) {
                  numBytes += clazz.data().length;
                  numFields += clazz.numberOfFields();
                  numDetachStates += clazz.numberOfDetachStates();
                  compiledClasses.add(clazz);
                }
  
                @Override
                public List<ClassData> getResult() {
                  logger.log(
                      Level.FINE,
                      "Compilation took {0}\n"
                          + "     templates: {1}\n"
                          + "       classes: {2}\n"
                          + "         bytes: {3}\n"
                          + "        fields: {4}\n"
                          + "  detachStates: {5}",
                      new Object[] {
                        stopwatch.toString(),
                        registry.getAllTemplates().size(),
                        compiledClasses.size(),
                        numBytes,
                        numFields,
                        numDetachStates
                      });
                  return compiledClasses;
                }
              });
      if (reporter.errorsSince(checkpoint)) {
        return Optional.absent();
      }
      CompiledTemplates templates =
          new CompiledTemplates(
              compilerRegistry.getDelegateTemplateNames(), new MemoryClassLoader(classes));
      stopwatch.reset().start();
      templates.loadAll(compilerRegistry.getTemplateNames());
      logger.log(Level.FINE, "Loaded all classes in {0}", stopwatch);
      return Optional.of(templates);
    }