blob: 52b1a289447dd20574e55cb74a2a96577910158e [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// Transformer used for pub serve and pub build
import 'dart:async';
import 'package:barback/barback.dart';
import 'package:code_transformers/assets.dart';
import 'package:code_transformers/messages/build_logger.dart';
import 'package:code_transformers/resolver.dart';
import 'package:code_transformers/src/dart_sdk.dart' as dart_sdk;
import 'package:html5lib/dom.dart' as dom;
import 'package:initialize/transformer.dart' show generateBootstrapFile;
import 'package:initialize/build/initializer_plugin.dart';
import 'package:path/path.dart' as path;
import 'package:web_components/transformer.dart';
import 'common.dart';
/// Public method that can be used inside any [Transformer] which already has a
/// [Resolver] and [Transform] to generate a bootstrap file for the
/// web_components package.
Asset generateWebComponentsBootstrap(Resolver resolver, Transform transform,
dom.Document document, AssetId scriptId, AssetId newScriptId,
{List<InitializerPlugin> extraPlugins: const []}) {
var htmlImportRecorder = new HtmlImportAnnotationRecorder();
var plugins = [htmlImportRecorder]..addAll(extraPlugins);
// Bootstrap the application using the `initialize` package and our
// plugins.
var initializeBootstrap = generateBootstrapFile(
resolver, transform, scriptId, newScriptId,
errorIfNotFound: false, plugins: plugins);
// Add all seen imports to the document, before the first dart script tag if
// it exists.
var dartScript =
for (var importPath in htmlImportRecorder.importPaths) {
var import = new dom.Element.tag('link')
..attributes = {'rel': 'import', 'href': importPath,};
document.head.insertBefore(import, dartScript);
return initializeBootstrap;
/// A [Transformer] which runs the `initialize` transformer with
/// some special plugins and also inlines the html imports.
class WebComponentsTransformer extends Transformer {
final Resolvers _resolvers;
TransformOptions options;
: _resolvers = new Resolvers.fromMock(dart_sdk.mockSdkSources);
bool isPrimary(AssetId id) {
if (options.entryPoints != null) {
return options.entryPoints.contains(id.path);
if (id.path == 'web/index.bootstrap.dart') return true;
// If no entry point is supplied, then any html file under web/ or test/ is
// an entry point.
return (id.path.startsWith('web/') || id.path.startsWith('test/')) &&
Future apply(Transform transform) {
var logger = new BuildLogger(transform);
var primaryInput = transform.primaryInput;
return primaryInput.readAsString().then((html) {
// Find the dart script in the page.
var doc = parseHtml(html,;
var mainScriptTag = doc.querySelector('script[type="$dartType"]');
var scriptId = uriToAssetId(,
mainScriptTag.attributes['src'], logger, mainScriptTag.sourceSpan);
return _resolvers.get(transform, [scriptId]).then((resolver) {
var newScriptId = new AssetId(scriptId.package,
var bootstrap = generateWebComponentsBootstrap(
resolver, transform, doc, scriptId, newScriptId);
// Swap out the main script tag for the bootstrap version.
mainScriptTag.attributes['src'] = path.url.relative(,
from: path.url.dirname(;
// Output the new document and bootstrap file.
.addOutput(new Asset.fromString(, doc.outerHtml));