Skip to content

Commit

Permalink
POC for opt-in SASS loader
Browse files Browse the repository at this point in the history
  • Loading branch information
aurelienshz committed Jan 21, 2018
1 parent eac8fce commit 8d679a4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 8 deletions.
18 changes: 18 additions & 0 deletions packages/react-dev-utils/optinSassWebpackLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports.default = function(source) {
try {
// XXX performance hit of calling require / require.resolve this for every file passed to this loader?
require.resolve('node-sass');

// Options are passed to loader using the function `this`. We use `bind`
// to transparently pass options coming from the webpack config to
// sass-loader:
// XXX performance hit of bind?
const sassLoader = require('sass-loader').bind(this);

return sassLoader(source);
} catch (er) {
throw new Error(
'It looks like you have required a .scss file. In order for this to work, you need to install node-sass and sass-loader first.'
);
}
};
7 changes: 5 additions & 2 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"printHostingInstructions.js",
"WatchMissingNodeModulesPlugin.js",
"WebpackDevServerUtils.js",
"webpackHotDevClient.js"
"webpackHotDevClient.js",
"optinSassWebpackLoader.js"
],
"dependencies": {
"@babel/code-frame": "7.0.0-beta.38",
Expand All @@ -59,7 +60,9 @@
"text-table": "0.2.0"
},
"devDependencies": {
"jest": "22.1.2"
"jest": "22.1.2",
"node-sass": "^4.7.2",
"sass-loader": "^6.0.6"
},
"scripts": {
"test": "jest"
Expand Down
39 changes: 33 additions & 6 deletions packages/react-scripts/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ dotenvFiles.forEach(dotenvFile => {
}
});

const appDirectory = fs.realpathSync(process.cwd());

/**
* Utility to parse PATH-like strings to array
*
* Separators:
* : in Unix (colon)
* ; in Windows (semicolon)
*
* @param {String} paths
* @returns {string}
*/
function parsePath(paths) {
if (paths) {
return paths
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
}

return '';
}

// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.
Expand All @@ -57,12 +81,14 @@ dotenvFiles.forEach(dotenvFile => {
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
process.env.NODE_PATH = parsePath(process.env.NODE_PATH);

// node-sass supports additional paths to resolve imports from.
// https://github.com/sass/node-sass/tree/v4.7.2#includepaths
// It works similar to NODE_PATH, but for importing scss files.
// We would like to assign an array to process.env variable, but
// Node will implicitly convert value to string.
process.env.SASS_INCLUDE_PATHS = parsePath(process.env.SASS_INCLUDE_PATHS);

// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
Expand All @@ -87,6 +113,7 @@ function getClientEnvironment(publicUrl) {
PUBLIC_URL: publicUrl,
}
);

// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
Expand Down
33 changes: 33 additions & 0 deletions packages/react-scripts/config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,39 @@ module.exports = {
},
],
},
// "react-dev-utils/optinSassWebpackLoader" wraps sass-loader, trying to require
// node-sass and sass-loader, and prompting the user to install them if it fails
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.scss$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 2,
},
},
{
loader: require.resolve('postcss-loader'),
options: postCSSLoaderOptions,
},
{
loader: require.resolve(
'react-dev-utils/optinSassWebpackLoader'
),
options: {
includePaths: process.env.SASS_INCLUDE_PATHS.split(
path.delimiter
),
},
},
],
},
// Allows you to use two kinds of imports for SVG:
// import logoUrl from './logo.svg'; gives you the URL.
// import { ReactComponent as Logo } from './logo.svg'; gives you a component.
Expand Down

0 comments on commit 8d679a4

Please sign in to comment.