I'm trying to write a custom Webpack loader that reads a JavaScript file and exports SASS variables, similar to js-to-sass-var-loader but with some added functionality.
/webpack-loaders/js-to-sass-loader.js
import _ from 'lodash';
import path from 'path';
const importRegex = /@import\s+'([^']+\.js)'\s*;/ig;
/*
functions for transforming...
*/
export default function (content) {
let self = this;
// search for "@import '*.js';" and replace that text with
// the transformed output of the specified JavaScript file
return content.replace(importRegex, (match, relativePath) => {
if (match) {
let modulePath = path.join(self.context, relativePath);
self.addDependency(modulePath);
let data = require(modulePath).default;
return transform(data);
}
});
}
This JavaScript file loads a .json config file, does a little processing and spits out an object.
/client/sass/sassConfig.js
import config from '../../config.json';
console.log('Generating SASS variables.');
let sass = {
// some special values here
};
for (let key of Object.keys(config.style)) {
sass[key] = config.style[key];
}
sass.debug = (process.env.NODE_ENV || 'production').trim() === 'development';
export default sass;
The json file includes comments, so I'm stripping them away with another trivial loader. This simply parses the json file using json5, then stringifies the output and passes it on.
/webpack-loaders/remove-json-comments-loader.js
import json5 from 'json5';
export default function (source) {
return JSON.stringify(json5.parse(source));
}
My webpack.config.babel.js includes rules for sass and json files to use these two loaders.
/webpack.config.babel.js
// ... imports ...
const webpackConfig = {
entry: {
app: './client/script.js',
},
output: {
filename: 'script.js',
path: path.resolve(__dirname, 'public')
},
resolveLoader: {
alias: {
'js-to-sass-loader': path.resolve(__dirname, 'webpack-loaders/js-to-sass-loader'),
'remove-json-comments-loader': path.resolve(__dirname, 'webpack-loaders/remove-json-comments-loader')
}
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.json$/,
exclude: /node_modules/,
loader: 'remove-json-comments-loader',
},
{
test: /\.s[ca]ss$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
{ loader: 'js-to-sass-loader' },
]
}),
},
// ...
],
},
plugins: [
// ...
new ExtractTextPlugin({ filename: 'style.css' }),
// ...
],
// ...
};
module.exports = webpackConfig;
In a few of my JavaScript files, I can import Config from './path/to/config.json'
with no problem. It correctly uses the remove-json-comments-loader
. But when my js-to-sass-loader
attempts to require sassConfig.js
, Webpack doesn't use the loader for parsing config.json
. It attempts to load it as a regular json file, which causes it to fail due to the comments. I've tried using import config from '!!remove-json-comments-loader!../../config.json';
but webpack says it cannot find the file.
I'm super new to writing webpack loaders, so I'm sure it's something simple. Help? Thanks!
Here's a link to the github repo: https://github.com/dfoverdx/PokeStreamer-Tools/tree/9b4c7315d5dc6b30c5972a0b8678489598311bf0
To reproduce the issue, open up /node/client/sass/sassConfig.js
, and change the first four lines to:
// import json5 from 'json5';
// import fs from 'fs';
// const config = json5.parse(fs.readFileSync('config.json'));
import config from '../../config.json';
That is, comment the first 3 lines and uncomment the 4th.
From /node
run npm run build
to produce the error.