7

Node.js が呼び出しを解決するために使用するアルゴリズムは、疑似コードrequire()で非常に明確に文書化されています。

@importSassの声明にも同じことが必要です。

インポート ファイルと同じディレクトリ、および構成された「ロード パス」のいずれかとの相対的なディレクトリで、拡張子およびを含むベース名および@import 'foo'のさまざまな組み合わせが試行されることはわかっています...しかし、これらはどのような順序で試行されますか。を満たすことができるファイルが複数ある場合は、 ?が優先されます。またはで開始すると、ロード パスを試行するかどうかに影響しますか? 私がカバーしていない他のことはありますか?ファイルはどうですか?foo_foo.scss.sass@import./../.css

このガイドは、「Sass は賢く、あなたに代わって解決してくれるでしょう」以上のことは何も述べていません。リファレンス ドキュメントでは詳細が説明されていますが、解決手順についてはまだ詳しく説明されていません。

疑似コードで、使用する正確なアルゴリズムを誰でも提供できますか?

4

1 に答える 1

6

の単純化されたアルゴリズムを次に示します@import <import_arg>;。これは、SASS のソース コードを読み、私自身のテストを実行した結果です。

def main(import_arg)
  let dirname = File.dirname(import_arg)
  let basename = File.basename(import_arg)
  if import_arg is absolute ... # omitted as this is a rare case
  else return search(dirname, basename)
end

# try resolving import argument relative to each path in load_paths
# 1. If we encounter an unambiguous match, we finish
# 2. If we encounter an ambiguous match, we give up
# see: https://stackoverflow.com/a/33588202/3649209
def search(dirname, basename)
  let cwd = operating system current working directory
  let load_paths = paths specified via SASS_PATH env variable and via --load-path options
  let search_paths = [cwd].concat(load_paths)
  for path in search_paths
    let file = find_match(File.expand_path(basename, path), basename)
    if (file != false) return file
  end
  throw "File to import not found or unreadable"
end

def find_match(directory, basename)
  let candidates = possible_files(directory, basename)
  if candiates.length == 0
    # not a single match found ... don't give up yet
    return false
  else if candidates.length > 1
    # several matching files, ambiguity! ... give up
    # throw ambiguity error
    throw "It's not clear which file to import"
  else
    # success! exactly one match found
    return candidates[0]
  end
end

# NB: this is a bit tricky to express in code
# which is why I settled for a high-level description
def possible_files(directory, basename)
  # if `basename` is of the form shown on the LHS
  # then check the filesystem for existence of
  # any of the files shown on the RHS within
  # directory `directory`. Return the list all the files
  # which do indeed exist (or [] if none exist).
  #   LHS        RHS
  #   x.sass -> _x.sass, x.sass
  #   x.scss -> _x.scss, x.scss
  #   x      -> x.scss, _x.scss, x.sass, _x.sass
  #   _x     -> _x.scss, _x.sass
end

簡潔にするために、私は Ruby の と Node.js の のようなものを使用File#dirnameしていFile#basenameます。Ruby に似た疑似コードを使用していますが、それでも疑似コードであることを意図しています。File#expandpath.resolve

キーポイント:

  • 優先順位はありません。優先順位を実装するのではなく、候補が複数ある場合、SASS はあきらめます。たとえば、書い@import "x"て両方x.scss_x.scss存在すると言うと、sass はあいまいなエラーをスローします。同様に、 と の両方x.scssx.sass存在する場合、あいまいエラーがスローされます。
  • ロード パスは「左から右」の順序で試行されます。それらは、インポートを解決するためのルートまたはベースを提供します (UNIX が $PATH を使用して実行可能ファイルを見つける方法と同様)。現在の作業ディレクトリが常に最初に試行されます。(ただし、この動作は3.2 から 3.4に変更されます)
  • ロード パスは、使用したかどうかに関係なく、常に試行されます./../
  • sass ファイルでは、通常の .css ファイルをインポートできません

詳細が必要な場合は、SASS のソース コードを読むことをお勧めします。

  • import方法sass/lib/sass/tree/import_node.rbsearch53 ~ 56 行目には、疑似コードの関数内と同じ for ループがあります。
  • 抽象Importers::Baseクラス。sass/lib/sass/importors/base.rbこのファイルのコメントは非常に便利です。
  • find_real_file方法sass/lib/sass/importors/filesystem.rb。行 112 ~ 126 で関数を実装していpossible_filesます。156 行目は、一致するものが 1 つしかないことを確認します。存在しない場合、167 行目であいまいなエラーがスローされます。そうでない場合、183 行目で一致するファイルが 1 つ選択されます。

編集:以前の回答に満足できなかったので、少し明確になるように書き直しました。アルゴリズムがファイル名のアンダースコアを正しく処理するようになりました (以前のアルゴリズムでは処理されませんでした)。また、OPが尋ねた他の質問に対処するための重要なポイントをいくつか追加しました。

于 2015-12-18T22:25:47.230 に答える