@emulsify/core 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.github/workflows/addtoprojects.yml +1 -1
  2. package/.storybook/main.js +11 -5
  3. package/.storybook/manager.js +1 -2
  4. package/.storybook/preview.js +2 -5
  5. package/.storybook/webpack.config.js +64 -12
  6. package/config/eslintrc.config.json +0 -1
  7. package/config/webpack/loaders.js +11 -3
  8. package/config/webpack/optimizers.js +18 -0
  9. package/config/webpack/plugins.js +52 -12
  10. package/config/webpack/resolves.js +79 -0
  11. package/config/webpack/sdc-loader.js +8 -0
  12. package/config/webpack/webpack.common.js +119 -23
  13. package/package.json +34 -28
  14. package/.history/.github/workflows/addtoprojects_20240130164835.yml +0 -21
  15. package/.history/.github/workflows/addtoprojects_20240607213528.yml +0 -21
  16. package/.history/.github/workflows/contributors_20240130164835.yml +0 -23
  17. package/.history/.github/workflows/contributors_20240607213836.yml +0 -23
  18. package/.history/.husky/commit-msg_20240729171216 +0 -4
  19. package/.history/.husky/commit-msg_20240729172358 +0 -2
  20. package/.history/.husky/pre-commit_20240729171216 +0 -4
  21. package/.history/.husky/pre-commit_20240729172429 +0 -2
  22. package/.history/.releaserc_20240607133550 +0 -11
  23. package/.history/.releaserc_20240607134831 +0 -18
  24. package/.history/.releaserc_20240607135005 +0 -11
  25. package/.history/.storybook/main_20240722083211.js +0 -153
  26. package/.history/.storybook/manager_20240311205454.js +0 -15
  27. package/.history/.storybook/manager_20240607162817.js +0 -15
  28. package/.history/.storybook/preview_20240401184023.js +0 -40
  29. package/.history/.storybook/preview_20240607162826.js +0 -40
  30. package/.history/.storybook/preview_20240610083720.js +0 -37
  31. package/.history/.storybook/preview_20240610083852.js +0 -30
  32. package/.history/.storybook/setupTwig.test_20240228163244.js +0 -33
  33. package/.history/.storybook/setupTwig.test_20240607163045.js +0 -33
  34. package/.history/.storybook/setupTwig_20240326081425.js +0 -59
  35. package/.history/.storybook/setupTwig_20240607163001.js +0 -43
  36. package/.history/.storybook/setupTwig_20240607163019.js +0 -43
  37. package/.history/README_20240312154948.md +0 -72
  38. package/.history/README_20240607162731.md +0 -94
  39. package/.history/config/a11y.config_20240607110020.js +0 -61
  40. package/.history/config/a11y.config_20240607163052.js +0 -61
  41. package/.history/config/a11y.config_20240607163120.js +0 -61
  42. package/.history/config/webpack/css/style_20240228152007.js +0 -1
  43. package/.history/config/webpack/css/style_20240607163238.js +0 -1
  44. package/.history/config/webpack/css_20240317194751.js +0 -1
  45. package/.history/config/webpack/css_20240607163108.js +0 -1
  46. package/.history/config/webpack/css_20240607163132.js +0 -1
  47. package/.history/config/webpack/loaders_20240730152304.js +0 -87
  48. package/.history/config/webpack/loaders_20240730152315.js +0 -87
  49. package/.history/config/webpack/loaders_20240731075844.js +0 -87
  50. package/.history/config/webpack/loaders_20240806083911.js +0 -88
  51. package/.history/config/webpack/loaders_20240806084032.js +0 -88
  52. package/.history/config/webpack/plugins_20240730152746.js +0 -77
  53. package/.history/config/webpack/plugins_20240730152818.js +0 -76
  54. package/.history/config/webpack/plugins_20240730153144.js +0 -76
  55. package/.history/config/webpack/plugins_20240730153215.js +0 -76
  56. package/.history/config/webpack/plugins_20240731075839.js +0 -48
  57. package/.history/config/webpack/svgSprite_20240401184053.js +0 -5
  58. package/.history/config/webpack/svgSprite_20240607163207.js +0 -5
  59. package/.history/config/webpack/webpack.common_20240730152548.js +0 -74
  60. package/.history/config/webpack/webpack.common_20240730152652.js +0 -76
  61. package/.history/config/webpack/webpack.common_20240731075910.js +0 -72
  62. package/.history/package-lock_20240722091648.json +0 -34023
  63. package/.history/package-lock_20240729171049.json +0 -34023
  64. package/.history/package-lock_20240729171107.json +0 -34023
  65. package/.history/package-lock_20240729171136.json +0 -34023
  66. package/.history/package_20240722085509.json +0 -135
  67. package/.history/package_20240722085523.json +0 -135
  68. package/.history/package_20240722085530.json +0 -135
  69. package/.history/package_20240722085550.json +0 -135
  70. package/.history/package_20240722085556.json +0 -135
  71. package/.history/package_20240722085606.json +0 -135
  72. package/.history/package_20240722091526.json +0 -135
  73. package/.history/package_20240722091548.json +0 -135
  74. package/.history/package_20240729171200.json +0 -135
  75. package/.history/package_20240729171707.json +0 -135
  76. package/.history/package_20240729171737.json +0 -135
  77. package/.history/package_20240729171750.json +0 -135
  78. package/.history/package_20240729171809.json +0 -135
  79. package/.history/package_20240729171834.json +0 -135
  80. package/.history/package_20240729171854.json +0 -135
  81. package/.history/package_20240729172054.json +0 -135
  82. package/.history/package_20240729172133.json +0 -135
  83. package/.history/package_20240729174630.json +0 -135
  84. package/.history/package_20240730153116.json +0 -136
  85. package/.history/package_20240806081212.json +0 -135
  86. package/.history/package_20240806081229.json +0 -135
  87. package/.history/package_20240806081258.json +0 -135
  88. package/.history/package_20240806081538.json +0 -135
  89. package/.history/package_20240806082035.json +0 -135
  90. package/.history/package_20240806082121.json +0 -135
  91. package/.history/package_20240806082142.json +0 -135
  92. package/.history/package_20240806082313.json +0 -135
  93. package/.history/package_20240806082418.json +0 -135
  94. package/.history/package_20240806083920.json +0 -135
  95. package/config/webpack/css/style.js +0 -1
  96. package/config/webpack/css.js +0 -1
@@ -18,4 +18,4 @@ jobs:
18
18
  # You can target a repository in a different organization
19
19
  # to the issue
20
20
  project-url: https://github.com/orgs/emulsify-ds/projects/6
21
- token: ${{ secrets.ADD_TO_PROJECT_PAT }}
21
+ github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
@@ -1,8 +1,15 @@
1
1
  const { configOverrides } = require('../../../../config/emulsify-core/storybook/main');
2
2
 
3
- const defaultConfig = {
3
+ const safeConfigOverrides = configOverrides || {};
4
+
5
+ const config = {
4
6
  stories: [
5
- '../../../../components/**/*.stories.@(js|jsx|ts|tsx)',
7
+ '../../../../(src|components)/**/*.stories.@(js|jsx|ts|tsx)',
8
+ ],
9
+ staticDirs: [
10
+ '../../../../assets/images',
11
+ '../../../../assets/icons',
12
+ '../../../../dist',
6
13
  ],
7
14
  addons: [
8
15
  '../../../@storybook/addon-a11y',
@@ -19,7 +26,7 @@ const defaultConfig = {
19
26
  options: {},
20
27
  },
21
28
  docs: {
22
- autodocs: true,
29
+ autodocs: false,
23
30
  },
24
31
  managerHead: (head) => `
25
32
  ${head}
@@ -146,8 +153,7 @@ const defaultConfig = {
146
153
  }
147
154
  </style>
148
155
  `,
156
+ ...safeConfigOverrides,
149
157
  };
150
158
 
151
- const config = Object.keys(configOverrides).length ? configOverrides : defaultConfig;
152
-
153
159
  module.exports = config;
@@ -1,5 +1,4 @@
1
- import { addons } from '@storybook/addons';
2
-
1
+ import { addons } from '@storybook/manager-api';
3
2
  import emulsifyTheme from './emulsifyTheme';
4
3
 
5
4
  import('../../../../config/emulsify-core/storybook/theme')
@@ -1,11 +1,8 @@
1
- import { useEffect } from '@storybook/client-api';
1
+ import { useEffect } from '@storybook/preview-api';
2
2
  import Twig from 'twig';
3
3
  import { setupTwig } from './setupTwig';
4
4
 
5
- // GLOBAL CSS
6
- import('../../../../dist/css/style.css');
7
-
8
- // Custom theme preview config if it exists.
5
+ // Project config to import stylesheets.
9
6
  import('../../../../config/emulsify-core/storybook/preview');
10
7
 
11
8
  // If in a Drupal project, it's recommended to import a symlinked version of drupal.js.
@@ -1,22 +1,66 @@
1
1
  const path = require('path');
2
2
  const globImporter = require('node-sass-glob-importer');
3
+
3
4
  const _StyleLintPlugin = require('stylelint-webpack-plugin');
4
- const { namespaces } = require('./setupTwig');
5
5
  const ESLintPlugin = require('eslint-webpack-plugin');
6
+ const resolves = require('../config/webpack/resolves');
7
+
8
+ // Emulsify project configuration.
9
+ const emulsifyConfig = require('../../../../project.emulsify.json');
10
+
11
+ /**
12
+ * Transforms namespace:component to @namespace/template/path
13
+ */
14
+ class ProjectNameResolverPlugin {
15
+ constructor(options = {}) {
16
+ this.prefix = options.projectName;
17
+ }
18
+
19
+ apply(resolver) {
20
+ const target = resolver.ensureHook('resolve');
21
+ resolver
22
+ .getHook('before-resolve')
23
+ .tapAsync('ProjectNameResolverPlugin', (request, resolveContext, callback) => {
24
+ const requestPath = request.request;
25
+
26
+ if (requestPath && requestPath.startsWith(`${this.prefix}:`)) {
27
+ const newRequestPath = requestPath.replace(`${this.prefix}:`, `${this.prefix}/`);
28
+ const newRequest = {
29
+ ...request,
30
+ request: newRequestPath,
31
+ };
32
+
33
+ resolver.doResolve(
34
+ target,
35
+ newRequest,
36
+ `Resolved ${this.prefix} URI: ${resolves.TwigResolve.alias[requestPath]}`,
37
+ resolveContext,
38
+ callback
39
+ );
40
+ } else {
41
+ callback();
42
+ }
43
+ });
44
+ }
45
+ }
6
46
 
7
47
  module.exports = async ({ config }) => {
48
+ // Alias
49
+ Object.assign(config.resolve.alias, resolves.TwigResolve.alias);
50
+
8
51
  // Twig
9
52
  config.module.rules.push({
10
53
  test: /\.twig$/,
11
54
  use: [
12
55
  {
13
- loader: 'twig-loader',
56
+ loader: path.resolve(__dirname, '../config/webpack/sdc-loader.js'),
14
57
  options: {
15
- twigOptions: {
16
- namespaces,
17
- },
58
+ projectName: emulsifyConfig.project.name,
18
59
  },
19
60
  },
61
+ {
62
+ loader: 'twigjs-loader',
63
+ },
20
64
  ],
21
65
  });
22
66
 
@@ -43,25 +87,33 @@ module.exports = async ({ config }) => {
43
87
  ],
44
88
  });
45
89
 
90
+ // YAML
91
+ config.module.rules.push({
92
+ test: /\.ya?ml$/,
93
+ loader: 'js-yaml-loader',
94
+ });
95
+
96
+ // Plugins
46
97
  config.plugins.push(
47
98
  new _StyleLintPlugin({
48
99
  configFile: path.resolve(__dirname, '../', '.stylelintrc.json'),
49
- context: path.resolve(__dirname, '../', 'components'),
100
+ context: path.resolve(__dirname, '../', 'src'),
50
101
  files: '**/*.scss',
51
102
  failOnError: false,
52
103
  quiet: false,
53
104
  }),
54
105
  new ESLintPlugin({
55
- context: path.resolve(__dirname, '../', 'components'),
106
+ context: path.resolve(__dirname, '../', 'src'),
56
107
  extensions: ['js'],
57
108
  }),
58
109
  );
59
110
 
60
- // YAML
61
- config.module.rules.push({
62
- test: /\.ya?ml$/,
63
- loader: 'js-yaml-loader',
64
- });
111
+ // Resolver Plugins
112
+ config.resolve.plugins = [
113
+ new ProjectNameResolverPlugin({
114
+ projectName: emulsifyConfig.project.name,
115
+ }),
116
+ ];
65
117
 
66
118
  return config;
67
119
  };
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "extends": [
3
- "airbnb-base",
4
3
  "eslint:recommended",
5
4
  "plugin:import/recommended",
6
5
  "plugin:security/recommended-legacy",
@@ -29,9 +29,8 @@ const JSLoader = {
29
29
  };
30
30
 
31
31
  const ImageLoader = {
32
- test: /\.(png|svg|jpg|gif)$/i,
33
- exclude: /icons\/.*\.svg$/,
34
- loader: 'file-loader',
32
+ test: /\.(png|jpe?g|gif)$/i,
33
+ type: 'asset',
35
34
  };
36
35
 
37
36
  const CSSLoader = {
@@ -76,13 +75,22 @@ const SVGSpriteLoader = {
76
75
  options: {
77
76
  extract: true,
78
77
  runtimeCompat: true,
78
+ outputPath: 'dist/',
79
79
  spriteFilename: './icons.svg',
80
80
  },
81
81
  };
82
82
 
83
+ const TwigLoader = {
84
+ test: /\.twig$/,
85
+ use: {
86
+ loader: 'twigjs-loader',
87
+ },
88
+ };
89
+
83
90
  module.exports = {
84
91
  JSLoader,
85
92
  CSSLoader,
86
93
  SVGSpriteLoader,
87
94
  ImageLoader,
95
+ TwigLoader,
88
96
  };
@@ -0,0 +1,18 @@
1
+ const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
2
+
3
+ const ImageMinimizer = new ImageMinimizerPlugin({
4
+ minimizer: {
5
+ implementation: ImageMinimizerPlugin.imageminMinify,
6
+ options: {
7
+ plugins: [
8
+ ['gifsicle', { interlaced: true }],
9
+ ['jpegtran', { progressive: true }],
10
+ ['optipng', { optimizationLevel: 5 }],
11
+ ],
12
+ },
13
+ },
14
+ });
15
+
16
+ module.exports = {
17
+ minimizer: [ImageMinimizer],
18
+ };
@@ -3,37 +3,77 @@ const path = require('path');
3
3
  const webpack = require('webpack');
4
4
  const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5
5
  const _MiniCssExtractPlugin = require('mini-css-extract-plugin');
6
- const _ImageminPlugin = require('imagemin-webpack-plugin').default;
7
6
  const _SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
7
+ const CopyPlugin = require('copy-webpack-plugin');
8
8
  const glob = require('glob');
9
+ const fs = require('fs-extra');
9
10
 
10
- const imagePath = path.resolve(__dirname, '../../../../../assets/images');
11
+ // Get directories for file contexts.
12
+ const projectDir = path.resolve(__dirname, '../../../../..');
13
+ const srcDir = path.resolve(projectDir, 'src');
11
14
 
15
+ // Emulsify project configuration.
16
+ const emulsifyConfig = require('../../../../../project.emulsify.json');
17
+
18
+ // Compress images plugin.
12
19
  const MiniCssExtractPlugin = new _MiniCssExtractPlugin({
13
20
  filename: '[name].css',
14
21
  chunkFilename: '[id].css',
15
22
  });
16
23
 
17
- const ImageminPlugin = new _ImageminPlugin({
18
- disable: process.env.NODE_ENV !== 'production',
19
- externalImages: {
20
- context: imagePath,
21
- sources: glob.sync(path.resolve(imagePath, '**/*.{png,jpg,gif,svg}')),
22
- destination: imagePath,
23
- },
24
- });
25
-
24
+ // Create SVG sprite.
26
25
  const SpriteLoaderPlugin = new _SpriteLoaderPlugin({
27
26
  plainSprite: true,
28
27
  });
29
28
 
29
+ // Enable Webpack progress plugin.
30
30
  const ProgressPlugin = new webpack.ProgressPlugin();
31
31
 
32
+ // Glob pattern for markup files.
33
+ const componentFilesPattern = path.resolve(srcDir, '**/*.{twig,yml}');
34
+
35
+ /**
36
+ * Prepare list of twig files to copy to "compiled" directories.
37
+ * @constructor
38
+ * @param {string} filesMatcher - Glob pattern.
39
+ */
40
+ function getPatterns(filesMatcher) {
41
+ const patterns = [];
42
+ glob.sync(filesMatcher).forEach((file) => {
43
+ const projectPath = file.split('/src/')[0];
44
+ const srcStructure = file.split(`${srcDir}/`)[1];
45
+ const parentDir = srcStructure.split('/')[0];
46
+ const filePath = file.split(/(foundation\/|components\/|layout\/)/)[2];
47
+ const consolidateDirs =
48
+ parentDir === 'layout' || parentDir === 'foundation'
49
+ ? '/components/'
50
+ : '/';
51
+ const newfilePath =
52
+ emulsifyConfig.project.platform === 'drupal'
53
+ ? `${projectPath}${consolidateDirs}${parentDir}/${filePath}`
54
+ : `${projectPath}/dist/${parentDir}/${filePath}`;
55
+ patterns.push({
56
+ from: file,
57
+ to: newfilePath,
58
+ });
59
+ });
60
+
61
+ return patterns;
62
+ }
63
+
64
+ // Copy twig files from src directory.
65
+ const CopyTwigPlugin = fs.existsSync(path.resolve(projectDir, 'src'))
66
+ ? new CopyPlugin({
67
+ patterns: getPatterns(componentFilesPattern),
68
+ })
69
+ : '';
70
+
71
+ // Export plugin configuration.
32
72
  module.exports = {
33
73
  ProgressPlugin,
34
74
  MiniCssExtractPlugin,
35
- ImageminPlugin,
36
75
  SpriteLoaderPlugin,
76
+ CopyTwigPlugin,
37
77
  CleanWebpackPlugin: new CleanWebpackPlugin({
38
78
  protectWebpackAssets: false, // Required for removal of extra, unwanted dist/css/*.js files.
39
79
  cleanOnceBeforeBuildPatterns: ['!*.{png,jpg,gif,svg}'],
@@ -0,0 +1,79 @@
1
+ const path = require('path');
2
+ const glob = require('glob');
3
+ const fs = require('fs-extra');
4
+
5
+ // Emulsify project configuration.
6
+ const emulsifyConfig = require('../../../../../project.emulsify.json');
7
+
8
+ // Get directories for file contexts.
9
+ const projectDir = path.resolve(__dirname, '../../../../..');
10
+ const projectName = emulsifyConfig.project.name;
11
+ const srcDir = fs.existsSync(path.resolve(projectDir, 'src'))
12
+ ? path.resolve(projectDir, 'src')
13
+ : path.resolve(projectDir, 'components');
14
+
15
+ // Glob pattern for twig aliases.
16
+ const aliasPattern = path.resolve(srcDir, '**/!(_*).twig');
17
+
18
+ /**
19
+ * Return all top-level directories from the projects source directory.
20
+ * @constructor
21
+ * @param {string} source - Path to source directory.
22
+ */
23
+ function getDirectories(source) {
24
+ const dirs = fs
25
+ .readdirSync(source, { withFileTypes: true }) // Read contents of the directory
26
+ .filter((dirent) => dirent.isDirectory()) // Filter only directories
27
+ .map((dirent) => dirent.name);
28
+ return dirs;
29
+ }
30
+
31
+ /**
32
+ * Return clean directory names if numbering is used for sorting.
33
+ * @constructor
34
+ * @param {string} dir - Given directory name.
35
+ */
36
+ function cleanDirectoryName(dir) {
37
+ if (/^\d{2}/.test(dir)) {
38
+ return dir.slice(3);
39
+ }
40
+ return dir;
41
+ }
42
+
43
+ /**
44
+ * Return a list of twig file file paths from the project source directory.
45
+ * @constructor
46
+ * @param {string} aliasMatcher - Glob pattern.
47
+ */
48
+ function getAliases(aliasMatcher) {
49
+ // Create default aliases
50
+ let aliases = {};
51
+ // Add SDC compatible aliases.
52
+ glob.sync(aliasMatcher).forEach((file) => {
53
+ const filePath = file.split(`${srcDir}/`)[1];
54
+ const fileName = path.basename(filePath);
55
+
56
+ if (emulsifyConfig.project.platform === 'drupal') {
57
+ aliases[`${projectName}/${fileName.replace('.twig', '')}`] = file;
58
+ }
59
+ });
60
+ // Add typical @namespace (path to directory) aliases for twig partials.
61
+ const dirs = getDirectories(srcDir);
62
+ dirs.forEach((dir) => {
63
+ const name = cleanDirectoryName(dir);
64
+ Object.assign(aliases, {
65
+ [`@${name}`]: `${projectDir}/${path.basename(srcDir)}/${dir}`,
66
+ });
67
+ });
68
+ return aliases;
69
+ }
70
+
71
+ // Alias twig namespaces.
72
+ const TwigResolve = {
73
+ extensions: ['.twig'],
74
+ alias: getAliases(aliasPattern),
75
+ };
76
+
77
+ module.exports = {
78
+ TwigResolve,
79
+ };
@@ -0,0 +1,8 @@
1
+ module.exports = function (source) {
2
+ const projectName = this.getOptions().projectName || '';
3
+ const result = source.replace(
4
+ new RegExp(`${projectName}:`, 'g'),
5
+ `${projectName}/`,
6
+ );
7
+ return result;
8
+ };
@@ -2,43 +2,129 @@ const path = require('path');
2
2
  const glob = require('glob');
3
3
  const loaders = require('./loaders');
4
4
  const plugins = require('./plugins');
5
+ const resolves = require('./resolves');
6
+ const optimizers = require('./optimizers');
7
+ const emulsifyConfig = require('../../../../../project.emulsify.json');
8
+ const fs = require('fs-extra');
5
9
 
10
+ // Get directories for file contexts.
6
11
  const webpackDir = path.resolve(__dirname);
7
- const rootDir = path.resolve(__dirname, '../../../../..');
8
- const distDir = path.resolve(__dirname, '../../../../../dist');
12
+ const projectDir = path.resolve(__dirname, '../../../../..');
13
+ const srcDir = fs.existsSync(path.resolve(projectDir, 'src'))
14
+ ? path.resolve(projectDir, 'src')
15
+ : path.resolve(projectDir, 'components');
9
16
 
10
17
  // Glob pattern for scss files that ignore file names prefixed with underscore.
11
- const scssPattern = path.resolve(rootDir, 'components/**/!(_*).scss');
18
+ const BaseScssPattern = fs.existsSync(path.resolve(projectDir, 'src'))
19
+ ? path.resolve(srcDir, '!(components|util)/**/!(_*|cl-*|sb-*).scss')
20
+ : '';
21
+ const ComponentScssPattern = fs.existsSync(path.resolve(projectDir, 'src'))
22
+ ? path.resolve(srcDir, 'components/**/!(_*|cl-*|sb-*).scss')
23
+ : path.resolve(srcDir, '**/!(_*|cl-*|sb-*).scss');
24
+ const ComponentLibraryScssPattern = path.resolve(srcDir, 'util/**/!(_).scss');
25
+
12
26
  // Glob pattern for JS files.
13
- const jsPattern = path.resolve(
14
- rootDir,
15
- 'components/**/!(*.stories|*.component|*.min|*.test).js',
16
- );
27
+ const jsPattern = fs.existsSync(path.resolve(projectDir, 'src'))
28
+ ? path.resolve(
29
+ srcDir,
30
+ 'components/**/!(*.stories|*.component|*.min|*.test).js',
31
+ )
32
+ : path.resolve(srcDir, '**/!(*.stories|*.component|*.min|*.test).js');
33
+
34
+ // Glob pattern for svgSprite config.
35
+ const spritePattern = path.resolve(webpackDir, 'svgSprite.js');
36
+
37
+ /**
38
+ * Return all scss/js/svg files that Webpack needs to compile.
39
+ * @constructor
40
+ * @param {string} str - Path to file.
41
+ * @param {string} replacement - string to replace str.
42
+ */
43
+ function replaceLastSlash(str, replacement) {
44
+ // Find the last occurrence of '/'
45
+ const lastSlashIndex = str.lastIndexOf('/');
46
+ // If there is no '/' in the string, return the original string
47
+ if (lastSlashIndex === -1) {
48
+ return str;
49
+ }
50
+ // Replace the last '/' with the specified replacement
51
+ return (
52
+ str.slice(0, lastSlashIndex) + replacement + str.slice(lastSlashIndex + 1)
53
+ );
54
+ }
17
55
 
18
- // Prepare list of scss and js file for "entry".
19
- function getEntries(scssMatcher, jsMatcher) {
56
+ /**
57
+ * Return all scss/js/svg files that Webpack needs to compile.
58
+ * @constructor
59
+ * @param {string} BaseScssMatcher - Glob pattern.
60
+ * @param {string} ComponentScssMatcher - Glob pattern.
61
+ * @param {string} ComponentLibraryScssMatcher - Glob pattern.
62
+ * @param {string} jsMatcher - Glob pattern.
63
+ * @param {string} spriteMatcher - Glob pattern.
64
+ */
65
+ function getEntries(
66
+ BaseScssMatcher,
67
+ ComponentScssMatcher,
68
+ ComponentLibraryScssMatcher,
69
+ jsMatcher,
70
+ spriteMatcher,
71
+ ) {
20
72
  const entries = {};
21
73
 
22
- // SCSS entries
23
- glob.sync(scssMatcher).forEach((file) => {
24
- const filePath = file.split('components/')[1];
25
- const newfilePath = `css/${filePath.replace('.scss', '')}`;
74
+ // Non-component or global SCSS entries.
75
+ glob.sync(BaseScssMatcher).forEach((file) => {
76
+ const filePath = file.split(`${srcDir}/`)[1];
77
+ const filePathDist = filePath.split('/')[1]
78
+ ? filePath.split('/')[1]
79
+ : filePath.split('/')[0];
80
+ const newfilePath = fs.existsSync(path.resolve(projectDir, 'src'))
81
+ ? `dist/global/${filePathDist.replace('.scss', '')}`
82
+ : `dist/css/${filePathDist.replace('.scss', '')}`;
26
83
  entries[newfilePath] = file;
27
84
  });
28
85
 
29
- // JS entries
30
- glob.sync(jsMatcher).forEach((file) => {
86
+ // Component SCSS entries.
87
+ glob.sync(ComponentScssMatcher).forEach((file) => {
31
88
  const filePath = file.split('components/')[1];
32
- const newfilePath = `js/${filePath.replace('.js', '')}`;
89
+ const filePathDist = replaceLastSlash(filePath, '/css/');
90
+ const distStructure = fs.existsSync(path.resolve(projectDir, 'src'))
91
+ ? 'components'
92
+ : 'css';
93
+ const newfilePath =
94
+ emulsifyConfig.project.platform === 'drupal' &&
95
+ fs.existsSync(path.resolve(projectDir, 'src'))
96
+ ? `components/${filePathDist.replace('.scss', '')}`
97
+ : `dist/${distStructure}/${filePathDist.replace('.scss', '')}`;
33
98
  entries[newfilePath] = file;
34
99
  });
35
100
 
36
- entries.svgSprite = path.resolve(webpackDir, 'svgSprite.js');
101
+ // Component Library SCSS entries.
102
+ glob.sync(ComponentLibraryScssMatcher).forEach((file) => {
103
+ const filePath = file.split(/util/)[1];
104
+ const newfilePath = `dist/storybook/${filePath.replace('.scss', '')}`;
105
+ entries[newfilePath] = file;
106
+ });
107
+
108
+ // JS entries.
109
+ glob.sync(jsMatcher).forEach((file) => {
110
+ if (!file.includes('dist/')) {
111
+ const filePath = file.split('components/')[1];
112
+ const filePathDist = replaceLastSlash(filePath, '/js/');
113
+ const distStructure = fs.existsSync(path.resolve(projectDir, 'src'))
114
+ ? 'components'
115
+ : 'js';
116
+ const newfilePath =
117
+ emulsifyConfig.project.platform === 'drupal' &&
118
+ fs.existsSync(path.resolve(projectDir, 'src'))
119
+ ? `components/${filePathDist.replace('.js', '')}`
120
+ : `dist/${distStructure}/${filePathDist.replace('.js', '')}`;
121
+ entries[newfilePath] = file;
122
+ }
123
+ });
37
124
 
38
- // CSS Files.
39
- glob.sync(`${webpackDir}/css/*js`).forEach((file) => {
40
- const baseFileName = path.basename(file);
41
- const newfilePath = `css/${baseFileName.replace('.js', '')}`;
125
+ glob.sync(spriteMatcher).forEach((file) => {
126
+ const filePath = file.split('/webpack/')[1];
127
+ const newfilePath = `dist/${filePath.replace('.js', '')}`;
42
128
  entries[newfilePath] = file;
43
129
  });
44
130
 
@@ -49,13 +135,20 @@ module.exports = {
49
135
  stats: {
50
136
  errorDetails: true,
51
137
  },
52
- entry: getEntries(scssPattern, jsPattern),
138
+ entry: getEntries(
139
+ BaseScssPattern,
140
+ ComponentScssPattern,
141
+ ComponentLibraryScssPattern,
142
+ jsPattern,
143
+ spritePattern,
144
+ ),
53
145
  module: {
54
146
  rules: [
55
147
  loaders.CSSLoader,
56
148
  loaders.SVGSpriteLoader,
57
149
  loaders.ImageLoader,
58
150
  loaders.JSLoader,
151
+ loaders.TwigLoader,
59
152
  ],
60
153
  },
61
154
  plugins: [
@@ -63,10 +156,13 @@ module.exports = {
63
156
  plugins.ImageminPlugin,
64
157
  plugins.SpriteLoaderPlugin,
65
158
  plugins.ProgressPlugin,
159
+ plugins.CopyTwigPlugin,
66
160
  plugins.CleanWebpackPlugin,
67
161
  ],
68
162
  output: {
69
- path: distDir,
163
+ path: `${projectDir}`,
70
164
  filename: '[name].js',
71
165
  },
166
+ resolve: resolves.TwigResolve,
167
+ optimization: optimizers,
72
168
  };