debian-mirror-gitlab/storybook/config/webpack.config.js
2023-01-12 18:35:48 +00:00

183 lines
5.9 KiB
JavaScript

/* eslint-disable no-param-reassign */
const { statSync } = require('fs');
const path = require('path');
const glob = require('glob');
const sass = require('sass');
const webpack = require('webpack');
const IS_EE = require('../../config/helpers/is_ee_env');
const IS_JH = require('../../config/helpers/is_jh_env');
const gitlabWebpackConfig = require('../../config/webpack.config');
const ROOT_PATH = path.resolve(__dirname, '..', '..');
const EMPTY_VUE_COMPONENT_PATH = path.join(
ROOT_PATH,
'app/assets/javascripts/vue_shared/components/empty_component.js',
);
const buildIncludePaths = (nodeSassIncludePaths, previouslyResolvedPath) => {
const includePaths = [];
if (path.isAbsolute(previouslyResolvedPath)) {
includePaths.push(path.dirname(previouslyResolvedPath));
}
return [...new Set([...includePaths, ...nodeSassIncludePaths.split(path.delimiter)])];
};
const resolveGlobUrl = (url, includePaths = []) => {
const filePaths = new Set();
if (glob.hasMagic(url)) {
includePaths.forEach((includePath) => {
const globPaths = glob.sync(url, { cwd: includePath });
globPaths.forEach((relativePath) => {
filePaths.add(
path
.resolve(includePath, relativePath)
// This fixes a problem with importing absolute paths on windows.
.split(`\\`)
.join(`/`),
);
});
});
return [...filePaths];
}
return null;
};
const ROOT = path.resolve(__dirname, '../../');
const TRANSPARENT_1X1_PNG =
'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==)';
const SASS_INCLUDE_PATHS = [
'app/assets/stylesheets',
'app/assets/stylesheets/_ee',
'app/assets/stylesheets/_jh',
'ee/app/assets/stylesheets',
'ee/app/assets/stylesheets/_ee',
'node_modules',
].map((p) => path.resolve(ROOT, p));
if (IS_JH) {
SASS_INCLUDE_PATHS.push(
...['jh/app/assets/stylesheets', 'jh/app/assets/stylesheets/_jh'].map((p) =>
path.resolve(ROOT, p),
),
);
}
/**
* Custom importer for node-sass, used when LibSass encounters the `@import` directive.
* Doc source: https://github.com/sass/node-sass#importer--v200---experimental
* @param {*} url the path in import as-is, which LibSass encountered.
* @param {*} prev the previously resolved path.
* @returns {Object | null} the new import string.
*/
function sassSmartImporter(url, prev) {
const nodeSassOptions = this.options;
const includePaths = buildIncludePaths(nodeSassOptions.includePaths, prev).filter(
(includePath) => !includePath.includes('node_modules'),
);
// GitLab extensively uses glob-style import paths, but
// Sass doesn't support glob-style URLs out of the box.
// Here, we try and resolve the glob URL.
// If it resolves, we update the @import statement with the resolved path.
const filePaths = resolveGlobUrl(url, includePaths);
if (filePaths) {
const contents = filePaths
.filter((file) => statSync(file).isFile())
.map((x) => `@import '${x}';`)
.join(`\n`);
return { contents };
}
return null;
}
const sassLoaderOptions = {
functions: {
'image-url($url)': function sassImageUrlStub() {
return new sass.types.String(TRANSPARENT_1X1_PNG);
},
'asset_path($url)': function sassAssetPathStub() {
return new sass.types.String(TRANSPARENT_1X1_PNG);
},
'asset_url($url)': function sassAssetUrlStub() {
return new sass.types.String(TRANSPARENT_1X1_PNG);
},
'url($url)': function sassUrlStub() {
return new sass.types.String(TRANSPARENT_1X1_PNG);
},
},
includePaths: SASS_INCLUDE_PATHS,
importer: sassSmartImporter,
};
module.exports = function storybookWebpackConfig({ config }) {
// Add any missing extensions from the main GitLab webpack config
config.resolve.extensions = Array.from(
new Set([...config.resolve.extensions, ...gitlabWebpackConfig.resolve.extensions]),
);
// Replace any Storybook-defined CSS loaders with our custom one.
config.module.rules = [
...config.module.rules.filter((r) => !r.test.test('.css')),
{
test: /\.s?css$/,
exclude: /typescale\/\w+_demo\.scss$/, // skip typescale demo stylesheets
loaders: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: sassLoaderOptions,
},
],
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
{
test: /\.(zip)$/,
loader: 'file-loader',
options: {
esModule: false,
},
},
];
// Silence webpack warnings about moment/pikaday not being able to resolve.
config.plugins.push(new webpack.IgnorePlugin(/moment/, /pikaday/));
if (!IS_EE) {
config.plugins.push(
new webpack.NormalModuleReplacementPlugin(/^ee_component\/(.*)\.vue/, (resource) => {
resource.request = EMPTY_VUE_COMPONENT_PATH;
}),
);
}
if (!IS_JH) {
config.plugins.push(
new webpack.NormalModuleReplacementPlugin(/^jh_component\/(.*)\.vue/, (resource) => {
resource.request = EMPTY_VUE_COMPONENT_PATH;
}),
);
}
const baseIntegrationTestHelpersPath = 'spec/frontend_integration/test_helpers';
// Add any missing aliases from the main GitLab webpack config
Object.assign(config.resolve.alias, gitlabWebpackConfig.resolve.alias, {
test_helpers: path.resolve(ROOT, baseIntegrationTestHelpersPath),
ee_else_ce_test_helpers: path.resolve(ROOT, IS_EE ? 'ee' : '', baseIntegrationTestHelpersPath),
test_fixtures: path.resolve(ROOT, 'tmp/tests/frontend', IS_EE ? 'fixtures-ee' : 'fixtures'),
});
// The main GitLab project aliases this `icons.svg` file to app/assets/javascripts/lib/utils/icons_path.js,
// which depends on the existence of a global `gon` variable.
// By deleting the alias, imports of this path will resolve as expected.
delete config.resolve.alias['@gitlab/svgs/dist/icons.svg'];
return config;
};