Skip to content

Commit

Permalink
Merge pull request #5 from homer0/homer0_svg
Browse files Browse the repository at this point in the history
Fix SVG loaders for SSR targets
  • Loading branch information
Leonardo Apiwan committed Apr 2, 2018
2 parents 2ad8e08 + b17d5c8 commit 2133085
Show file tree
Hide file tree
Showing 2 changed files with 603 additions and 35 deletions.
172 changes: 148 additions & 24 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,23 @@ class ProjextReactPlugin {
*/
constructor() {
/**
* A list of reducer events the service will listen for in order to intercept rules
* configurations and update them.
* @type {Array}
* The name of the reducer event the service will listen in order to intercept the rules for
* JS files and update them.
* @type {string}
*/
this.jsRulesEvent = 'webpack-js-rules-configuration';
/**
* The name of the reducer event the service will listen in order to intercept the rules for
* fonts files, and if the target implements SSR, update them.
* @type {string}
*/
this.fontsRulesEvent = 'webpack-fonts-rules-configuration';
/**
* The name of the reducer event the service will listen in order to intercept the rules for
* images files, and if the target implements SSR, update them.
* @type {string}
*/
this.rulesEventsNames = [
'webpack-js-rules-configuration-for-node',
'webpack-js-rules-configuration-for-browser',
];
this.imagesRulesEvent = 'webpack-images-rules-configuration';
/**
* The name of the reducer event the service will listen for and use to update a target entry
* settings if the target `hot` property is `true`.
Expand Down Expand Up @@ -63,19 +72,25 @@ class ProjextReactPlugin {
}
/**
* This is the method called when the plugin is loaded by projext. It just gets the events service
* and registers the listeners for the reducer events that handles JS rules and target
* configuration.
* and registers the listeners for the reducer events that handle the JS rules, fonts rules,
* images rules and target configuration.
* @param {Projext} app The projext main container.
*/
register(app) {
const events = app.get('events');
// Add the listeners for the rules.
this.rulesEventsNames.forEach((eventName) => {
events.on(eventName, (rules, params) => (
this.updateRules(rules, params.target, app.get('targets'))
));
});
// Add the listener for the target.
// Add the listener for the JS files rules event.
events.on(this.jsRulesEvent, (rules, params) => (
this.updateJSRules(rules, params.target, app.get('targets'))
));
// Add the listener for the font files rules event.
events.on(this.fontsRulesEvent, (rules, params) => (
this.updateFontsRules(rules, params.target, app.get('targets'))
));
// Add the listener for the font files rules event.
events.on(this.imagesRulesEvent, (rules, params) => (
this.updateImagesRules(rules, params.target, app.get('targets'))
));
// Add the listener for the target configuration event.
events.on(
this.targetEventName,
(config, params) => this.updateTargetConfiguration(config, params.target)
Expand All @@ -86,11 +101,11 @@ class ProjextReactPlugin {
* settings and makes the necessary modifications to the Babel loader configuration.
* @param {Array} currentRules The list of JS rules for the webpack configuration.
* @param {Target} target The target information.
* @param {Targets} targets The targets service, to get the information of of targets the
* @param {Targets} targets The targets service, to get the information of targets the
* one being processed may need for SSR.
* @return {Array} The updated list of rules.
*/
updateRules(currentRules, target, targets) {
updateJSRules(currentRules, target, targets) {
let updatedRules;
// If the target `framework` setting is the right one...
if (target.framework === this.frameworkProperty) {
Expand All @@ -102,12 +117,8 @@ class ProjextReactPlugin {
const babelLoaderIndex = this._findBabelLoaderIndex(baseJSRule.use);
// If the Babel loader is preset...
if (babelLoaderIndex > -1) {
// ...merge the default options withy any overwrite the target may have.
const options = Object.assign(
{},
this.frameworkOptions,
target.frameworkOptions || {}
);
// ...get the framework options for the target.
const options = this._getTargetOptions(target);
// Push the paths for SSR targets
baseJSRule.include.push(...options.ssr.map((name) => {
const targetInfo = targets.getTarget(name);
Expand All @@ -125,8 +136,93 @@ class ProjextReactPlugin {
updatedRules = currentRules;
}

// Return the updated rules
return currentRules;
}
/**
* This method gets called when projext reduces the fonts files rules of a target. It validates
* the target settings, and if the target implements SSR, it adds the `include` setting on
* the SVG rule for the SSR targets directories.
* @param {Array} currentRules The list of fonts rules for the webpack configuration.
* @param {Target} target The target information.
* @param {Targets} targets The targets service, to get the SSR targets information.
* @return {Array} The updated list of rules.
*/
updateFontsRules(currentRules, target, targets) {
let updatedRules;
// If the target `framework` setting is the right one...
if (target.framework === this.frameworkProperty) {
// ...copy the list of rules.
updatedRules = currentRules.slice();
// Find the loader used for SVG files.
const svgLoader = updatedRules.find((rule) => '.svg'.match(rule.test));
// If the loader was found...
if (svgLoader) {
// ...get the target framework options.
const options = this._getTargetOptions(target);
// If the `include` option is a list, keep it like that, otherwise, convert it into a list.
const include = Array.isArray(svgLoader.include) ?
svgLoader.include :
[svgLoader.include];

// Loop all the possible SSR targets and add their _"fonts path"_ to the `include` option.
include.push(...options.ssr.map((name) => (
this._getTargetFontsRegExp(targets.getTarget(name))
)));

// Overwrite the SVG loder `include` option.
svgLoader.include = include;
}
} else {
// ...otherwise, just set to return the received rules.
updatedRules = currentRules;
}

// Return the updated rules.
return updatedRules;
}
/**
* This method gets called when projext reduces the images files rules of a target. It validates
* the target settings, and if the target implements SSR, it adds the `exclude` setting on
* the SVG rule for the SSR targets fonts directories.
* @param {Array} currentRules The list of fonts rules for the webpack configuration.
* @param {Target} target The target information.
* @param {Targets} targets The targets service, to get the SSR targets information.
* @return {Array} The updated list of rules.
*/
updateImagesRules(currentRules, target, targets) {
let updatedRules;
// If the target `framework` setting is the right one...
if (target.framework === this.frameworkProperty) {
// ...copy the list of rules.
updatedRules = currentRules.slice();
// Find the loader used for SVG files.
const svgLoader = updatedRules.find((rule) => '.svg'.match(rule.test));
// If the loader was found...
if (svgLoader) {
// ...get the target framework options.
const options = this._getTargetOptions(target);
// If the `exclude` option is a list, keep it like that, otherwise, convert it into a list.
const exclude = Array.isArray(svgLoader.exclude) ?
svgLoader.exclude :
[svgLoader.exclude];

// Loop all the possible SSR targets and add their _"fonts path"_ to the `exclude` option.
exclude.push(...options.ssr.map((name) => (
this._getTargetFontsRegExp(targets.getTarget(name))
)));

// Overwrite the SVG loder `exclude` option.
svgLoader.exclude = exclude;
}
} else {
// ...otherwise, just set to return the received rules.
updatedRules = currentRules;
}

// Return the updated rules.
return updatedRules;
}
/**
* This method gets called when projext reduces a target configuration for Wepack. It validates
* the target settings and if HMR is enabled, it updates the `entry` setting with the required
Expand Down Expand Up @@ -164,6 +260,34 @@ class ProjextReactPlugin {

return updatedConfiguration;
}
/**
* Merge the default framework options with the overwrites the target may have, and return the
* dictionary with the _"final options"_, ready to use.
* @param {Target} target The target information.
* @return {Object}
* @ignore
* @access protected
*/
_getTargetOptions(target) {
return Object.assign(
{},
this.frameworkOptions,
target.frameworkOptions || {}
);
}
/**
* Gets the RegExp for a fonts folder inside a given target source directory. This is used on
* the fonts SVG loader to `include` the files and on the images SVG loader to `exclude` them,
* that way SVG files inside a folder that matches the RegExp get handled as fonts and if they
* don't match it, they get handled as images.
* @param {Target} target The target information.
* @return {RegExp}
* @ignore
* @access protected
*/
_getTargetFontsRegExp(target) {
return new RegExp(`${target.paths.source}/(?:.*?/)?fonts/.*?`, 'i');
}
/**
* Finds the index of the Babel loader on a list of loaders.
* @param {Array} loaders The list of loaders.
Expand Down
Loading

0 comments on commit 2133085

Please sign in to comment.