Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/stop with svg sprites #347

Closed
wants to merge 11 commits into from
73 changes: 51 additions & 22 deletions config/loaders.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require('path')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const srcPath = path.resolve(__dirname, '../src')
const nodeModulesPath = path.resolve(__dirname, '../node_modules')
Expand All @@ -12,15 +13,15 @@ module.exports = {
const isProduction = mode === 'production'

return [
/* FontsLoader */ {
{
test: /\.(woff|woff2)$/,
type: 'asset/resource',
include: [srcPath + '/fonts', nodeModulesPath + '/@fontsource-variable', nodeModulesPath + '/@fontsource'],
generator: {
filename: 'fonts/[name][ext][query]',
},
},
/* ImagesLoader */ {
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/resource',
exclude: /icons/,
Expand All @@ -29,7 +30,53 @@ module.exports = {
filename: 'images/[name][ext][query]',
},
},
/* JSLoader */ {
{
test: /\.svg$/,
type: 'asset/resource',
include: srcPath + '/img/icons',
generator: {
filename: 'images/icons/[name][ext][query]',
},
use: {
loader: ImageMinimizerPlugin.loader,
options: {
minimizer: {
implementation: ImageMinimizerPlugin.svgoMinify,
options: {
encodeOptions: {
// Pass over SVGs multiple times to ensure all optimizations are applied. False by default
multipass: true,
plugins: [
{
name: 'preset-default',
},
{
name: 'addAttributesToSVGElement',
params: {
attributes: [
{
focusable: false,
},
{
'aria-hidden': true,
},
],
},
},
{
name: 'addClassesToSVGElement',
params: {
classNames: ['icon', '$class_names'],
},
},
],
},
},
},
},
},
},
{
test: /\.js$/i,
include: srcPath + '/js',
use: {
Expand All @@ -41,7 +88,7 @@ module.exports = {
},
},
},
/* SCSSLoader */ {
{
test: /\.(scss|css)$/,
include: srcPath + '/scss',
use: [
Expand Down Expand Up @@ -103,24 +150,6 @@ module.exports = {
},
],
},
/* SVGLoader */ {
test: /\.svg$/,
include: srcPath + '/img/icons',
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
publicPath: 'icons/',
spriteFilename: (svgPath) => `${/icons([\\|/])(.*?)\1/gm.exec(svgPath)[2]}.svg`,
symbolId: (filePath) => `icon-${path.basename(filePath).slice(0, -4)}`,
},
},
{
loader: 'svgo-loader',
},
],
},
]
},
}
12 changes: 3 additions & 9 deletions config/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const BrowserSyncPlugin = require('browser-sync-webpack-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const StyleLintPlugin = require('stylelint-webpack-plugin')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin')
const WebpackBar = require('webpackbar')
const DependencyExtractionWebpackPlugin = require('@wordpress/dependency-extraction-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
Expand All @@ -21,9 +20,6 @@ module.exports = {
context: path.resolve(__dirname, '../src/js'),
files: '**/*.js',
}),
new SpriteLoaderPlugin({
plainSprite: true,
}),
new StyleLintPlugin({
configFile: path.resolve(__dirname, '../.stylelintrc'),
context: path.resolve(__dirname, '../src/scss'),
Expand All @@ -32,6 +28,9 @@ module.exports = {
new WebpackBar({
color: '#ffe600',
}),
new WebpackManifestPlugin({
fileName: 'assets.json',
}),
new DependencyExtractionWebpackPlugin(),
]

Expand All @@ -40,11 +39,6 @@ module.exports = {
new BundleAnalyzerPlugin({
analyzerMode: 'json',
generateStatsFile: true,
})
)
plugins.push(
new WebpackManifestPlugin({
fileName: 'assets.json',
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].min.css',
Expand Down
38 changes: 0 additions & 38 deletions config/svgo.config.js

This file was deleted.

3 changes: 0 additions & 3 deletions config/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const path = require('path')
const entries = require('./entries')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const svgoconfig = require('./svgo.config')

module.exports = {
entry: entries,
Expand All @@ -24,8 +23,6 @@ module.exports = {
['gifsicle', { interlaced: true }],
['jpegtran', { progressive: true }],
['optipng', { optimizationLevel: 5 }],
// Svgo configuration here https://github.com/svg/svgo#configuratio
['svgo', { svgoconfig }],
],
},
},
Expand Down
15 changes: 8 additions & 7 deletions inc/Helpers/Svg.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,30 @@
/**
* @usage BEA\Theme\Framework\Helpers\Svg\get_the_icon( 'like' );
*
* @param string $icon_class
* @param array $additionnal_classes
* @param string $icon_name
* @param array $additionnal_classes
*
* @return string
*/
function get_the_icon( string $icon_class, $additionnal_classes = [] ): string {
firestar300 marked this conversation as resolved.
Show resolved Hide resolved
function get_the_icon( string $icon_name, array $additionnal_classes = [] ): string {
/**
* @var Svg $svg
*/
$svg = \BEA\Theme\Framework\Framework::get_container()->get_service( 'svg' );
return false !== $svg ? $svg->get_the_icon( $icon_class, $additionnal_classes ) : '';
return false !== $svg ? $svg->get_the_icon( $icon_name, $additionnal_classes ) : '';
}

/**
* @usage BEA\Theme\Framework\Helpers\Svg\the_icon( 'like' );
*
* @param string $icon_class
* @param string $icon_name
* @param array $additionnal_classes
*
*/
function the_icon( string $icon_class, $additionnal_classes = [] ): void {
function the_icon( string $icon_name, array $additionnal_classes = [] ): void {
/**
* @var Svg $svg
*/
$svg = \BEA\Theme\Framework\Framework::get_container()->get_service( 'svg' );
false !== $svg ? $svg->the_icon( $icon_class, $additionnal_classes ) : '';
false !== $svg ? $svg->the_icon( $icon_name, $additionnal_classes ) : '';
}
13 changes: 11 additions & 2 deletions inc/Services/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,15 @@ public function stylesheet_uri( string $stylesheet_uri ): string {
* @return string
*/
public function get_min_file( string $type ): string {
static $cache_data;

if ( isset( $cache_data[ $type ] ) ) {
return $cache_data[ $type ];
}

if ( empty( $type ) ) {
return '';
$cache_data[ $type ] = '';
return $cache_data[ $type ];
}

if ( ! file_exists( \get_theme_file_path( '/dist/assets.json' ) ) ) {
Expand Down Expand Up @@ -176,7 +183,9 @@ public function get_min_file( string $type ): string {
return '';
}

return $file;
$cache_data[ $type ] = $file;

return $cache_data[ $type ];
}

/**
Expand Down
41 changes: 21 additions & 20 deletions inc/Services/Svg.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace BEA\Theme\Framework\Services;

use BEA\Theme\Framework\Framework;
use BEA\Theme\Framework\Service;
use BEA\Theme\Framework\Service_Container;

Expand All @@ -11,11 +12,16 @@
* @package BEA\Theme\Framework
*/
class Svg implements Service {
/**
* @var Assets;
*/
private $assets;

/**
* @param Service_Container $container
*/
public function register( Service_Container $container ): void {
$this->assets = Framework::get_container()->get_service( 'assets' );
add_filter( 'wp_kses_allowed_html', [ $this, 'allow_svg_tag' ] );
}

Expand All @@ -33,41 +39,36 @@ public function get_service_name(): string {
}

/**
* @param string $icon_class
* @param string $icon_name
* @param array $additionnal_classes
*
* @return string
*/
public function get_the_icon( string $icon_class, array $additionnal_classes = [] ): string {
if ( empty( $icon_class ) ) {
public function get_the_icon( string $icon_name, array $additionnal_classes = [] ): string {
if ( empty( $icon_name ) ) {
return '';
}

// acf-svg-icon already return sprite-name.svg#icon-name, ex: social.svg#icon-facebook
// format the string to obtain sprite-name/icon-name
$icon_class = str_replace( '.svg#icon-', '/', $icon_class );
$icon_path = sprintf( '/dist/%s', $this->assets->get_min_file( sprintf( 'images/icons/%s.svg', $icon_name ) ) );

$sprite_name = 'sprite';

if ( false !== strpos( $icon_class, '/' ) ) {
$sprite_name = strtok( $icon_class, '/' );
$icon_class = substr( $icon_class, strpos( $icon_class, '/' ) + 1 );
if ( ! file_exists( \get_theme_file_path( $icon_path ) ) ) {
return '';
}

$icon_slug = strpos( $icon_class, 'icon-' ) === 0 ? $icon_class : sprintf( 'icon-%s', $icon_class );
$classes = [ 'icon', $icon_slug ];
$classes = array_merge( $classes, $additionnal_classes );
$classes = array_map( 'sanitize_html_class', $classes );
$classes = implode( ' ', array_map( 'sanitize_html_class', array_merge( [ 'icon-' . $icon_name ], $additionnal_classes ) ) );

return sprintf( '<svg class="%s" aria-hidden="true" focusable="false"><use href="%s#%s"></use></svg>', implode( ' ', $classes ), \get_theme_file_uri( sprintf( '/dist/icons/%s.svg', $sprite_name ) ), $icon_slug ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$html = file_get_contents( \get_theme_file_path( $icon_path ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

return preg_replace( '/\$class_names/i', $classes, $html );
firestar300 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @param string $icon_class
* @param array $additionnal_classes
* @param string $icon_name
* @param array $additionnal_classes
*
*/
public function the_icon( string $icon_class, array $additionnal_classes = [] ): void {
echo $this->get_the_icon( $icon_class, $additionnal_classes ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
public function the_icon( string $icon_name, array $additionnal_classes = [] ): void {
echo $this->get_the_icon( $icon_name, $additionnal_classes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}

/**
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"imagemin": "^8.0.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-mozjpeg": "^10.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"js-yaml": "^4.1.0",
Expand All @@ -65,9 +66,7 @@
"stylelint-config-recess-order": "^3.0.0",
"stylelint-scss": "^4.3.0",
"stylelint-webpack-plugin": "^3.3.0",
"svg-sprite-loader": "^6.0.10",
"svgo": "^3.0.2",
"svgo-loader": "^3.0.0",
"svgo": "^3.2.0",
"terser-webpack-plugin": "^5.3.6",
"webpack": "^5.35.0",
"webpack-bundle-analyzer": "^4.4.1",
Expand Down
9 changes: 1 addition & 8 deletions src/js/post-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,4 @@ function requireAll(r) {
r.keys().forEach(r)
}

// SVG
requireAll(require.context('../img/icons', true, /\.svg$/))

// DEFAULT
requireAll(require.context('../img/default', true, /\.(png|jpe?g)$/))

// STATIC
requireAll(require.context('../img/static', true, /\.(png|jpe?g|gif)$/))
requireAll(require.context('../img', true, /\.(png|jpe?g|gif|svg)$/))
Loading
Loading