Don't create an intermediate stylesheet for @import if possible

We really only need this stylesheet when we're resolving imported
cross-module @extends, which doesn't come up very often.
This commit is contained in:
Natalie Weizenbaum 2019-07-16 02:35:31 +01:00
parent c8770da29b
commit 0f8f7577a5
3 changed files with 66 additions and 11 deletions

View File

@ -2,6 +2,8 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:collection';
import 'package:source_span/source_span.dart';
import '../../../visitor/interface/statement.dart';
@ -12,6 +14,11 @@ import '../../../parse/scss.dart';
import '../../../syntax.dart';
import '../statement.dart';
import 'parent.dart';
import 'forward_rule.dart';
import 'loud_comment.dart';
import 'silent_comment.dart';
import 'use_rule.dart';
import 'variable_declaration.dart';
/// A Sass stylesheet.
///
@ -22,8 +29,28 @@ class Stylesheet extends ParentStatement {
/// Whether this was parsed from a plain CSS stylesheet.
final bool plainCss;
/// All the `@use` rules that appear in this stylesheet.
List<UseRule> get uses => UnmodifiableListView(_uses);
final _uses = <UseRule>[];
/// All the `@forward` rules that appear in this stylesheet.
List<ForwardRule> get forwards => UnmodifiableListView(_forwards);
final _forwards = <ForwardRule>[];
Stylesheet(Iterable<Statement> children, this.span, {this.plainCss = false})
: super(List.unmodifiable(children));
: super(List.unmodifiable(children)) {
for (var child in this.children) {
if (child is UseRule) {
_uses.add(child);
} else if (child is ForwardRule) {
_forwards.add(child);
} else if (child is! SilentComment &&
child is! LoudComment &&
child is! VariableDeclaration) {
break;
}
}
}
/// Parses a stylesheet from [contents] according to [syntax].
///

View File

@ -1111,9 +1111,24 @@ class _EvaluateVisitor
_activeModules.add(url);
// TODO(nweiz): If [stylesheet] contains no `@use` or `@forward` rules, just
// evaluate it directly in [_root] rather than making a new
// [ModifiableCssStylesheet] and manually copying members.
// If the imported stylesheet doesn't use any modules, we can inject its
// CSS directly into the current stylesheet. If it does use modules, we
// need to put its CSS into an intermediate [ModifiableCssStylesheet] so
// that we can hermetically resolve `@extend`s before injecting it.
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
var environment = _environment.global();
await _withEnvironment(environment, () async {
var oldImporter = _importer;
var oldStylesheet = _stylesheet;
_importer = importer;
_stylesheet = stylesheet;
await visitStylesheet(stylesheet);
_importer = oldImporter;
_stylesheet = oldStylesheet;
});
_activeModules.remove(url);
return;
}
List<ModifiableCssNode> children;
var environment = _environment.global();

View File

@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_evaluate.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: 7169a54c3952c7708141a4cec606dee0c8ba4f2d
// Checksum: c8527e9c89f7ebbab760b62b70da66d1b01b2bf3
//
// ignore_for_file: unused_import
@ -556,9 +556,7 @@ class _EvaluateVisitor
/// If [clone] is `true`, this will copy the modules before extending them so
/// that they don't modify [root] or its dependencies.
CssStylesheet _combineCss(Module<Callable> root, {bool clone = false}) {
// TODO(nweiz): short-circuit if no upstream modules (transitively) include
// any CSS.
if (root.upstream.isEmpty) {
if (!root.upstream.any((module) => module.transitivelyContainsCss)) {
var selectors = root.extender.simpleSelectors;
var unsatisfiedExtension = firstOrNull(root.extender
.extensionsWhereTarget((target) => !selectors.contains(target)));
@ -1114,9 +1112,24 @@ class _EvaluateVisitor
_activeModules.add(url);
// TODO(nweiz): If [stylesheet] contains no `@use` or `@forward` rules, just
// evaluate it directly in [_root] rather than making a new
// [ModifiableCssStylesheet] and manually copying members.
// If the imported stylesheet doesn't use any modules, we can inject its
// CSS directly into the current stylesheet. If it does use modules, we
// need to put its CSS into an intermediate [ModifiableCssStylesheet] so
// that we can hermetically resolve `@extend`s before injecting it.
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
var environment = _environment.global();
_withEnvironment(environment, () {
var oldImporter = _importer;
var oldStylesheet = _stylesheet;
_importer = importer;
_stylesheet = stylesheet;
visitStylesheet(stylesheet);
_importer = oldImporter;
_stylesheet = oldStylesheet;
});
_activeModules.remove(url);
return;
}
List<ModifiableCssNode> children;
var environment = _environment.global();