Webpack'ing "sass" (dart-sass), использует динамически, жесткие зависимости кода в контексте? - PullRequest
2 голосов
/ 18 июня 2019

Задача

Пакет "sass" содержит модуль, sass.dart.js: https://runpkg.com/?sass@1.21.0/sass.dart.js

Среди прочего, он содержит динамическое использование require (много строк отредактировано):

var self = Object.create(global);
self.require = require;

//...

u($,"N0","Hq",function(){return self.require("readline")})
u($,"Mr","cN",function(){return self.require("fs")})
u($,"MN","Ho",function(){return self.require("chokidar")})

Такое использование require предотвращает статический анализ с помощью веб-пакета, что приводит к ошибке в выходных данных (также в этой сущности) и к созданию веб-пакета EmptyContext в пакете. Это естественно не работает:)

Опции опробованы

Я видел ContextReplacementPlugin, я не думаю, что это применимо здесь, поскольку использование не является прямым вызовом по требованию.

Я видел noParse, но похоже на ядерный подход, и я не знаю, какими могут быть потенциальные негативные побочные эффекты.

Код репродукции

Также в этот гист

index.js:

const sass = require("sass");
console.log(sass);

webpack.config.js:

module.exports = (env) => ({
    entry: "./index.js",
    mode: "development",
    target: "node"
});

package.json:

{
  "devDependencies": {
    "webpack": "^4.34.0",
    "webpack-cli": "^3.3.4"
  },
  "dependencies": {
    "sass": "^1.21.0"
  },
  "scripts": {
    "build": "webpack-cli"
  }
}

Цель

Как я могу сконфигурировать контекст для этого конкретного модуля, чтобы конкретно перечислять readline / fs / chokidar как зависимости, возможно, чтобы создать некоторый контекст, который предоставляет только эти значения?

Я не против, если решение немного хрупкое и потребует закрепления версии dart-sass.

1 Ответ

0 голосов
/ 19 июня 2019

Мы пришли к «решению», которое реализует специальный загрузчик, специфичный для dart-sass, для добавления кода в модуль для обхода статического анализа.

SASS-PREPEND-loader.js:

const SASS_PREPEND_CODE = `require = (function () {
  var fs = require("fs");
  var readline = require("readline");
  return function (mod) {
    switch (mod) {
      case "fs": return fs;
      case "readline": return readline;
      default: throw new Error("Unexpected sass dependency");
    }
  };
})();`

module.exports = function(source) {
    this.cacheable();
    this.callback(null, `${SASS_PREPEND_CODE}\n${source}`);
};

webpack.config.js (отрывок):

module: {
    rules: [
        {
            resource: path.resolve(__dirname, "node_modules", "sass", "sass.dart.js"),
            loader: path.resolve(__dirname, "sass-prepend-loader.js"),
        }
    ],
},

Это специально для текущей версии "sass", 1.20.3, и, возможно, также для поведения в текущем веб-пакете. Примечание: мы не проходим через зависимость "chokidar", наш вариант использования не требует этого.

Он работает, назначая require с версией, которая может обслуживать только "fs" и "readline". Webpack заменяет вызовы replace на вызовы __webpack_require__ (удовлетворяющие его желание статического анализа) и позволяет require (теперь скрыт) оставаться на месте.

Извлечь из dist / index.js:

/***/ (function(module, exports, __webpack_require__) {

(function(module, exports, __webpack_require__) {

eval("/* WEBPACK VAR INJECTION */(function(__filename) {var require;require = (function () {\n  var fs = __webpack_require__(/*! fs */ \"fs\");\n  var readline = __webpack_require__(/*! readline */ \"readline\");\n  return function (mod) {\n    switch (mod) {\n      case \"fs\": return fs;\n      case \"readline\": return readline;\n      default: throw new Error(\"Unexpected sass dependency\");\n    }\n  };\n})();\n// make sure to keep this as 'var'\n// we don't want block scoping\nvar self = Object.create(global);\n\nself.scheduleImmediate = self.setImmediate\n    ? function (cb) {\n        global.setImmediate(cb);\n      }\n    : function(cb) {\n        setTimeout(cb, 0);\n      };\n\nself.require = require;

//...

self.require(\"fs\")

Надеюсь, что это временное решение и что мы можем найти лучшее решение по одному из следующих путей:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...