Skip to content

Commit

Permalink
Refactor code (#826)
Browse files Browse the repository at this point in the history
* refactor: `loader-utils`

* refactor: variable names

* refactor: code
  • Loading branch information
evilebottnawi committed Nov 30, 2018
1 parent ee409c5 commit 255c0f0
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 132 deletions.
173 changes: 90 additions & 83 deletions lib/loader.js
Expand Up @@ -7,13 +7,19 @@ const localByDefault = require('postcss-modules-local-by-default');
const extractImports = require('postcss-modules-extract-imports');
const modulesScope = require('postcss-modules-scope');
const modulesValues = require('postcss-modules-values');
const loaderUtils = require('loader-utils');
const {
getOptions,
isUrlRequest,
urlToRequest,
getRemainingRequest,
getCurrentRequest,
stringifyRequest,
} = require('loader-utils');

const { importParser, icssParser, urlParser } = require('./plugins');
const {
getLocalIdent,
getImportPrefix,
placeholderImportItemReplacer,
compileExports,
placholderRegExps,
} = require('./utils');
Expand All @@ -22,7 +28,7 @@ const CssSyntaxError = require('./CssSyntaxError');

module.exports = function loader(content, map) {
const callback = this.async();
const options = loaderUtils.getOptions(this) || {};
const options = getOptions(this) || {};
const sourceMap = options.sourceMap || false;

/* eslint-disable no-param-reassign */
Expand All @@ -43,40 +49,38 @@ module.exports = function loader(content, map) {
}
/* eslint-enable no-param-reassign */

const parserOptions = {};
const resolveImport = options.import !== false;
const resolveUrl = options.url !== false;
const loaderContext = this;
const localIdentName = options.localIdentName || '[hash:base64]';
const customGetLocalIdent = options.getLocalIdent || getLocalIdent;

const parserOptions = {
url: options.url !== false,
import: options.import !== false,
};

const plugins = [
modulesValues,
localByDefault({
mode: options.modules ? 'local' : 'global',
rewriteUrl(global, url) {
if (parserOptions.url) {
if (resolveUrl) {
// eslint-disable-next-line no-param-reassign
url = url.trim();

if (
!url.replace(/\s/g, '').length ||
!loaderUtils.isUrlRequest(url)
) {
if (!url.replace(/\s/g, '').length || !isUrlRequest(url)) {
return url;
}

if (global) {
return loaderUtils.urlToRequest(url);
return urlToRequest(url);
}
}

return url;
},
}),
extractImports(),
modulesScope({
generateScopedName: function generateScopedName(exportName) {
const localIdentName = options.localIdentName || '[hash:base64]';
const customGetLocalIdent = options.getLocalIdent || getLocalIdent;

return customGetLocalIdent(loaderContext, localIdentName, exportName, {
regExp: options.localIdentRegExp,
hashPrefix: options.hashPrefix || '',
Expand All @@ -86,11 +90,11 @@ module.exports = function loader(content, map) {
}),
];

if (options.import !== false) {
if (resolveImport) {
plugins.push(importParser(parserOptions));
}

if (options.url !== false) {
if (resolveUrl) {
plugins.push(urlParser(parserOptions));
}

Expand All @@ -99,12 +103,10 @@ module.exports = function loader(content, map) {
postcss(plugins)
.process(content, {
// we need a prefix to avoid path rewriting of PostCSS
from: `/css-loader!${loaderUtils
.getRemainingRequest(this)
from: `/css-loader!${getRemainingRequest(this)
.split('!')
.pop()}`,
to: loaderUtils
.getCurrentRequest(this)
to: getCurrentRequest(this)
.split('!')
.pop(),
map: options.sourceMap
Expand All @@ -121,78 +123,83 @@ module.exports = function loader(content, map) {
.warnings()
.forEach((warning) => this.emitWarning(new Warning(warning)));

// for importing CSS
const importUrlPrefix = getImportPrefix(this, options);
const { camelCase, exportOnlyLocals, importLoaders } = options;
const { importItems, urlItems, exports } = parserOptions;
// Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
const importUrlPrefix = getImportPrefix(this, importLoaders);
// Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
const importItemReplacer = (item) => {
const match = placholderRegExps.importItem.exec(item);
const idx = +match[1];
const importItem = importItems[idx];
const importUrl = importUrlPrefix + importItem.url;

if (exportOnlyLocals) {
return `" + require(${stringifyRequest(
this,
importUrl
)})[${JSON.stringify(importItem.export)}] + "`;
}

let exportJs = compileExports(
parserOptions.exports,
placeholderImportItemReplacer(
return `" + require(${stringifyRequest(
this,
parserOptions.importItems,
importUrlPrefix,
options.exportOnlyLocals
),
options.camelCase
);
importUrl
)}).locals[${JSON.stringify(importItem.export)}] + "`;
};

if (options.exportOnlyLocals) {
if (exportJs) {
exportJs = `module.exports = ${exportJs};`;
}
let exportCode = compileExports(exports, camelCase, (valueAsString) =>
valueAsString.replace(placholderRegExps.importItemG, importItemReplacer)
);

return callback(null, exportJs);
if (exportOnlyLocals) {
return callback(
null,
exportCode ? `module.exports = ${exportCode};` : exportCode
);
}

let cssAsString = JSON.stringify(result.css);

const alreadyImported = {};
const importJs = parserOptions.importItems
const importCode = importItems
.filter((imp) => {
if (!imp.media) {
if (alreadyImported[imp.url]) {
return false;
}

alreadyImported[imp.url] = true;
}

return true;
})
.map((imp) => {
const { url } = imp;
const media = imp.media || '';

if (!loaderUtils.isUrlRequest(url)) {
if (!isUrlRequest(url)) {
return `exports.push([module.id, ${JSON.stringify(
`@import url(${url});`
)}, ${JSON.stringify(media)}]);`;
}

const importUrl = importUrlPrefix + url;

return `exports.i(require(${loaderUtils.stringifyRequest(
return `exports.i(require(${stringifyRequest(
this,
importUrl
)}), ${JSON.stringify(media)});`;
}, this)
.join('\n');

cssAsString = cssAsString.replace(
let cssAsString = JSON.stringify(result.css).replace(
placholderRegExps.importItemG,
placeholderImportItemReplacer(
this,
parserOptions.importItems,
importUrlPrefix
)
importItemReplacer
);

// helper for ensuring valid CSS strings from requires
let urlEscapeHelper = '';

if (
options.url !== false &&
parserOptions.urlItems &&
parserOptions.urlItems.length > 0
) {
urlEscapeHelper = `var escape = require(${loaderUtils.stringifyRequest(
let urlEscapeHelperCode = '';

if (resolveUrl && urlItems && urlItems.length > 0) {
urlEscapeHelperCode = `var escape = require(${stringifyRequest(
this,
require.resolve('./runtime/escape.js')
)});\n`;
Expand All @@ -202,7 +209,7 @@ module.exports = function loader(content, map) {
(item) => {
const match = placholderRegExps.urlItem.exec(item);
let idx = +match[1];
const urlItem = parserOptions.urlItems[idx];
const urlItem = urlItems[idx];
const { url } = urlItem;

idx = url.indexOf('?#');
Expand All @@ -217,66 +224,66 @@ module.exports = function loader(content, map) {
// idx === 0 is catched by isUrlRequest
// in cases like url('webfont.eot?#iefix')
urlRequest = url.substr(0, idx);
return `" + escape(require(${loaderUtils.stringifyRequest(
return `" + escape(require(${stringifyRequest(
this,
urlRequest
)}) + "${url.substr(idx)}") + "`;
}

urlRequest = url;

return `" + escape(require(${loaderUtils.stringifyRequest(
return `" + escape(require(${stringifyRequest(
this,
urlRequest
)})) + "`;
}
);
}

if (exportJs) {
exportJs = `exports.locals = ${exportJs};`;
if (exportCode) {
exportCode = `exports.locals = ${exportCode};`;
}

let moduleJs;
if (sourceMap && result.map) {
/* eslint-disable no-param-reassign */
let newMap = result.map;

if (sourceMap && newMap) {
// Add a SourceMap
map = result.map.toJSON();
newMap = newMap.toJSON();

if (map.sources) {
map.sources = map.sources.map(
if (newMap.sources) {
newMap.sources = newMap.sources.map(
(source) =>
source
.split('!')
.pop()
.replace(/\\/g, '/'),
this
);
map.sourceRoot = '';
newMap.sourceRoot = '';
}

map.file = map.file
newMap.file = newMap.file
.split('!')
.pop()
.replace(/\\/g, '/');
map = JSON.stringify(map);
/* eslint-enable no-param-reassign */

moduleJs = `exports.push([module.id, ${cssAsString}, "", ${map}]);`;
} else {
moduleJs = `exports.push([module.id, ${cssAsString}, ""]);`;
newMap = JSON.stringify(newMap);
}

const runtimeCode = `exports = module.exports = require(${stringifyRequest(
this,
require.resolve('./runtime/api')
)})(${!!sourceMap});`;
const moduleCode = `exports.push([module.id, ${cssAsString}, ""${
newMap ? `,${newMap}` : ''
}]);`;

// Embed runtime
return callback(
null,
`${urlEscapeHelper}exports = module.exports = require(${loaderUtils.stringifyRequest(
this,
require.resolve('./runtime/api.js')
)})(${sourceMap});\n` +
`// imports\n${importJs}\n\n` +
`// module\n${moduleJs}\n\n` +
`// exports\n${exportJs}`
`${urlEscapeHelperCode}${runtimeCode}\n` +
`// imports\n${importCode}\n\n` +
`// module\n${moduleCode}\n\n` +
`// exports\n${exportCode}`
);
})
.catch((error) => {
Expand Down

0 comments on commit 255c0f0

Please sign in to comment.