Skip to content

Commit

Permalink
Allow to use Dart Sass instead of Node Sass
Browse files Browse the repository at this point in the history
  • Loading branch information
Lyrkan committed Feb 10, 2019
1 parent f35841a commit 1346ee5
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 31 deletions.
2 changes: 1 addition & 1 deletion lib/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const features = {
method: 'enableSassLoader()',
packages: [
{ name: 'sass-loader', enforce_version: true },
{ name: 'node-sass' }
[{ name: 'node-sass' }, { name: 'sass' }]
],
description: 'load Sass files'
},
Expand Down
103 changes: 74 additions & 29 deletions lib/package-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,20 @@ function getInstallCommand(packageConfigs) {
const hasYarnLockfile = fs.existsSync('yarn.lock');
const hasNpmLockfile = fs.existsSync('package-lock.json');
const packageInstallStrings = packageConfigs.map((packageConfig) => {
if (typeof packageConfig.version === 'undefined') {
return packageConfig.name;
const firstPackage = packageConfig[0];

if (typeof firstPackage.version === 'undefined') {
return firstPackage.name;
}

// e.g. ^4.0||^5.0: use the latest version
let recommendedVersion = packageConfig.version;
let recommendedVersion = firstPackage.version;
if (recommendedVersion.indexOf('||') !== -1) {
recommendedVersion = recommendedVersion.split('|').pop().trim();
}

// recommend the version included in our package.json file
return `${packageConfig.name}@${recommendedVersion}`;
return `${firstPackage.name}@${recommendedVersion}`;
});

if (hasNpmLockfile && !hasYarnLockfile) {
Expand All @@ -57,13 +59,32 @@ function getInstallCommand(packageConfigs) {
return chalk.yellow(`yarn add ${packageInstallStrings.join(' ')} --dev`);
}

function isPackageInstalled(packageConfig) {
try {
require.resolve(packageConfig.name);
return true;
} catch (e) {
return false;
}
}

function getPackageVersion(packageConfig) {
try {
return require(`${packageConfig.name}/package.json`).version;
} catch (e) {
return null;
}
}

function getMissingPackageRecommendations(packagesConfig, requestedFeature = null) {
let missingPackageConfigs = [];

for (let packageConfig of packagesConfig) {
try {
require.resolve(packageConfig.name);
} catch (e) {
if (!Array.isArray(packageConfig)) {
packageConfig = [packageConfig];
}

if (!packageConfig.some(isPackageInstalled)) {
missingPackageConfigs.push(packageConfig);
}
}
Expand All @@ -72,8 +93,18 @@ function getMissingPackageRecommendations(packagesConfig, requestedFeature = nul
return;
}

const missingPackageNamesChalked = missingPackageConfigs.map(function(packageConfig) {
return chalk.green(packageConfig.name);
const missingPackageNamesChalked = missingPackageConfigs.map(function(packageConfigs) {
const packageNames = packageConfigs.map(packageConfig => {
return chalk.green(packageConfig.name);
});

let missingPackages = packageNames[0];
if (packageNames.length > 1) {
const alternativePackages = packageNames.slice(1);
missingPackages = `${missingPackages} (or ${alternativePackages.join(' or ')})`;
}

return missingPackages;
});

let message = `Install ${missingPackageNamesChalked.join(' & ')}`;
Expand All @@ -89,45 +120,56 @@ function getMissingPackageRecommendations(packagesConfig, requestedFeature = nul
};
}

function getInvalidPackageVersionRecommendations(packagesConfig, requestedFeature) {
let badVersionMessages = [];
function getInvalidPackageVersionRecommendations(packagesConfig) {
const processPackagesConfig = (packageConfig) => {
if (Array.isArray(packageConfig)) {
let messages = [];

for (const config of packageConfig) {
messages = messages.concat(processPackagesConfig(config));
}

return messages;
}

for (let packageConfig of packagesConfig) {
if (typeof packageConfig.version === 'undefined') {
continue;
return [];
}

let version;
try {
version = require(`${packageConfig.name}/package.json`).version;
} catch (e) {
// should not happen because this functions is meant to be
// called only after verifying a package is actually installed
throw new Error(`Could not find package.json file for ${packageConfig.name}`);
const version = getPackageVersion(packageConfig);

// If version is null at this point it should be because
// of an optional dependency whose presence has already
// been checked before.
if (version === null) {
return [];
}

if (semver.satisfies(version, packageConfig.version)) {
continue;
return [];
}

if (semver.gtr(version, packageConfig.version)) {
badVersionMessages.push(
return [
`Webpack Encore requires version ${chalk.green(packageConfig.version)} of ${chalk.green(packageConfig.name)}. Your version ${chalk.green(version)} is too new. The related feature *may* still work properly. If you have issues, try downgrading the library, or upgrading Encore.`
);
];
} else {
badVersionMessages.push(
return [
`Webpack Encore requires version ${chalk.green(packageConfig.version)} of ${chalk.green(packageConfig.name)}, but your version (${chalk.green(version)}) is too old. The related feature will probably *not* work correctly.`
);
];
}
}
};

return badVersionMessages;
return processPackagesConfig(packagesConfig);
}

function addPackagesVersionConstraint(packages) {
const packageJsonData = require('../package.json');
const addConstraint = (packageData) => {
if (Array.isArray(packageData)) {
return packageData.map(addConstraint);
}

return packages.map(packageData => {
const newData = Object.assign({}, packageData);

if (packageData.enforce_version) {
Expand All @@ -143,7 +185,10 @@ function addPackagesVersionConstraint(packages) {
}

return newData;
});
};


return packages.map(addConstraint);
}

module.exports = {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@
"postcss-loader": "^3.0.0",
"preact": "^8.2.1",
"preact-compat": "^3.17.0",
"sass": "^1.17.0",
"sass-loader": "^7.0.1",
"sinon": "^2.3.4",
"strip-ansi": "^5.0.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
"ts-loader": "^5.3.0",
Expand Down
5 changes: 4 additions & 1 deletion test/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,10 @@ describe('Functional tests using webpack', function() {
config.setPublicPath('/build');
config.addStyleEntry('bg', './css/background_image.scss');
config.addStyleEntry('font', './css/roboto_font.css');
config.enableSassLoader();
config.enableSassLoader(options => {
// Use sass-loader instead of node-sass
options.implementation = require('sass');
});

testSetup.runWebpack(config, (webpackAssert) => {
expect(config.outputPath).to.be.a.directory()
Expand Down
27 changes: 27 additions & 0 deletions test/package-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const packageHelper = require('../lib/package-helper');
const path = require('path');
const process = require('process');
const fs = require('fs');
const stripAnsi = require('strip-ansi');

describe('package-helper', () => {
const baseCwd = process.cwd();
Expand All @@ -29,6 +30,7 @@ describe('package-helper', () => {
{ name: 'foo' }, { name: 'webpack' }, { name: 'bar' }
]);
expect(packageRecommendations.installCommand).to.contain('yarn add foo bar');
expect(stripAnsi(packageRecommendations.message)).to.contain('foo & bar');
});

it('missing packages with package-lock.json only', () => {
Expand All @@ -37,6 +39,7 @@ describe('package-helper', () => {
{ name: 'foo' }, { name: 'webpack' }, { name: 'bar' }
]);
expect(packageRecommendations.installCommand).to.contain('npm install foo bar');
expect(stripAnsi(packageRecommendations.message)).to.contain('foo & bar');
});

it('missing packages with yarn.lock only', () => {
Expand All @@ -45,6 +48,7 @@ describe('package-helper', () => {
{ name: 'foo' }, { name: 'webpack' }, { name: 'bar' }
]);
expect(packageRecommendations.installCommand).to.contain('yarn add foo bar');
expect(stripAnsi(packageRecommendations.message)).to.contain('foo & bar');
});

it('missing packages with both package-lock.json and yarn.lock', () => {
Expand All @@ -53,6 +57,19 @@ describe('package-helper', () => {
{ name: 'foo' }, { name: 'webpack' }, { name: 'bar' }
]);
expect(packageRecommendations.installCommand).to.contain('yarn add foo bar');
expect(stripAnsi(packageRecommendations.message)).to.contain('foo & bar');
});

it('missing packages with alternative packages', () => {
process.chdir(path.join(__dirname, '../fixtures/package-helper/yarn'));
const packageRecommendations = packageHelper.getMissingPackageRecommendations([
{ name: 'foo' },
[{ name: 'bar' }, { name: 'baz' }],
[{ name: 'qux' }, { name: 'corge' }, { name: 'grault' }],
[{ name: 'quux' }, { name: 'webpack' }],
]);
expect(packageRecommendations.installCommand).to.contain('yarn add foo bar qux');
expect(stripAnsi(packageRecommendations.message)).to.contain('foo & bar (or baz) & qux (or corge or grault)');
});
});

Expand Down Expand Up @@ -91,6 +108,16 @@ describe('package-helper', () => {

expect(packageRecommendations.installCommand).to.contain('yarn add foo@^8.0 bar');
});

it('Recommends correct install with alternative packages', () => {
const packageRecommendations = packageHelper.getMissingPackageRecommendations([
{ name: 'foo', version: '^7.0 || ^8.0' },
[{ name: 'bar' }, { name: 'baz' }],
[{ name: 'qux', version: '^1.0' }, { name: 'quux', version: '^2.0' }]
]);

expect(packageRecommendations.installCommand).to.contain('yarn add foo@^8.0 bar qux@^1.0');
});
});

describe('The getInvalidPackageVersionRecommendations correctly checks installed versions', () => {
Expand Down
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,11 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=

ansi-regex@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==

ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
Expand Down Expand Up @@ -7548,6 +7553,13 @@ sass-loader@^7.0.1:
neo-async "^2.5.0"
pify "^3.0.0"

sass@^1.17.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.17.0.tgz#e370b9302af121c9eadad5639619127772094ae6"
integrity sha512-aFi9RQqrCYkHB2DaLKBBbdUhos1N5o3l1ke9N5JqWzgSPmYwZsdmA+ViPVatUy/RPA21uejgYVUXM7GCh8lcdw==
dependencies:
chokidar "^2.0.0"

sax@0.5.x:
version "0.5.8"
resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
Expand Down Expand Up @@ -8097,6 +8109,13 @@ strip-ansi@^4.0.0:
dependencies:
ansi-regex "^3.0.0"

strip-ansi@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f"
integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==
dependencies:
ansi-regex "^4.0.0"

strip-bom@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
Expand Down

0 comments on commit 1346ee5

Please sign in to comment.