diff --git a/webpack5/package.json b/webpack5/package.json new file mode 100644 index 0000000..3e361c3 --- /dev/null +++ b/webpack5/package.json @@ -0,0 +1,177 @@ +{ + "name": "ss-webpack-boilerplate", + "version": "2.0.2", + "description": "Lets you create SilverStripe faster", + "author": "Tony Air ", + "license": "MIT", + "private": false, + "repository": { + "type": "git", + "url": "git+https://github.com/a2nt/silverstripe-webpack" + }, + "engines": { + "yarn": ">= 1.0.0" + }, + "scripts": { + "start": "cross-env NODE_ENV=development webpack-dev-server --https --config webpack.config.serve.js", + "dash": "cross-env NODE_ENV=development webpack-dashboard -- webpack-dev-server --config webpack.config.serve.js", + "prebuild": "rimraf ./app/client/dist", + "build": "cross-env NODE_ENV=production webpack --progress --stats-all", + "lint:check": "eslint ./app/client/src --config .eslintrc && sass-lint ./app/client/src --config .sasslintrc -v -q", + "lint:fix": "eslint ./app/client/src --config .eslintrc --fix && sass-lint ./app/client/src --config .sasslintrc -v -q --fix", + "lint:js": "eslint ./app/client/src --config .eslintrc", + "lint:sass": "sass-lint ./app/client/src --config .sasslintrc -v -q", + "prunecaches": "rimraf ./node_modules/.cache/", + "postinstall": "npm run prunecaches", + "postuninstall": "npm run prunecaches", + "preinstall": "npx only-allow pnpm" + }, + "browserslist": [ + "defaults", + "ie>=11" + ], + "dependencies": { + "@a2nt/meta-lightbox": "^2.4.0", + "@a2nt/ss-bootstrap-ui-webpack-boilerplate": "^2.6.3", + "aos": "^2.3.4", + "bootbox": "^5.5.2", + "bootstrap": "^4.5.3", + "bootstrap-confirmation2": "^4.1.0", + "bootstrap-datepicker": "^1.9.0", + "bootstrap-offcanvas": "^1.0.0", + "bootstrap-table": "^1.18.1", + "bootstrap-timepicker": "^0.5.2", + "font-awesome": "^4.7.0", + "hammerjs": "^2.0.8", + "inputmask": "^5.0.5", + "jquery": "^3.5.1", + "jquery-hammerjs": "^2.0.0", + "jquery-hoverintent": "*", + "jquery-zoom": "^1.7.21", + "jquery.appear": "^1.0.1", + "jquery.instagramFeed": "github:jsanahuja/jquery.instagramFeed", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "mapbox-gl": "^2.0.1", + "material-design-color": "^2.3.2", + "moment": "^2.29.1", + "offcanvas-bootstrap": "^2.5.2", + "popper.js": "*", + "select2": "^4.0.13", + "setimmediate": "^1.0.5", + "smooth-scroll": "^16.1.3", + "sticky-sidebar": "^3.3.1", + "tablednd": "^1.0.5", + "yarn": "^1.22.10" + }, + "devDependencies": { + "@a2nt/image-sprite-webpack-plugin": "^0.2.5", + "@babel/core": "^7.12.10", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-transform-react-jsx": "^7.12.12", + "@babel/preset-env": "^7.12.11", + "@googlemaps/markerclustererplus": "*", + "animate.css": "^4.1.1", + "ansi-html": "^0.0.7", + "ansi-regex": "^5.0.0", + "autoprefixer": "^10.1.0", + "babel-eslint": "^10.1.0", + "babel-loader": "^8.2.2", + "copy-webpack-plugin": "^7.0.0", + "croppie": "^2.6.5", + "cross-env": "^7.0.3", + "css-loader": "^5.0.1", + "eslint": "^7.16.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jquery": "^1.5.1", + "eslint-plugin-react": "^7.21.5", + "exif-js": "^2.3.0", + "exports-loader": "^1.1.1", + "fast-levenshtein": "^3.0.0", + "fastest-levenshtein": "^1.0.12", + "favicons-webpack-plugin": "^4.2.0", + "file-loader": "^6.2.0", + "font-awesome": "^4.7.0", + "hoist-non-react-statics": "^3.3.2", + "html-entities": "^1.4.0", + "html-webpack-plugin": "^4.5.0", + "image-minimizer-webpack-plugin": "^2.1.0", + "imagemin-jpegtran": "^7.0.0", + "img-optimize-loader": "^1.0.7", + "loglevel": "^1.7.1", + "mini-css-extract-plugin": "^1.3.3", + "node-sass": "^5.0.0", + "object-assign": "^4.1.1", + "optimize-css-assets-webpack-plugin": "^5.0.4", + "postcss-loader": "^4.1.0", + "prop-types": "^15.7.2", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "react-hot-loader": "^4.13.0", + "react-is": "^17.0.1", + "react-lifecycles-compat": "^3.0.4", + "resolve-url-loader": "^3.1.2", + "rimraf": "^3.0.2", + "routie": "0.0.1", + "sass-lint": "^1.13.1", + "sass-lint-fix": "^1.12.1", + "sass-loader": "^10.1.0", + "scheduler": "^0.20.1", + "script-ext-html-webpack-plugin": "^2.1.5", + "shallowequal": "^1.1.0", + "sockjs-client": "^1.5.0", + "strip-ansi": "^6.0.0", + "style-loader": "^2.0.0", + "svg-url-loader": "^7.1.1", + "terser-webpack-plugin": "^5.0.3", + "url-loader": "^4.1.1", + "webpack": "^5.11.0", + "webpack-cli": "^4.2.0", + "webpack-dev-server": "^4.0.0-beta.0", + "webpack-manifest-plugin": "^3.0.0", + "webpack-merge": "^5.7.3" + }, + "stylelint": { + "rules": { + "block-no-empty": null, + "color-no-invalid-hex": true, + "comment-empty-line-before": [ + "always", + { + "ignore": [ + "stylelint-commands", + "after-comment" + ] + } + ], + "declaration-colon-space-after": "always", + "indentation": [ + 4, + { + "except": [ + "value" + ] + } + ], + "max-empty-lines": 2, + "rule-empty-line-before": [ + "always", + { + "except": [ + "first-nested" + ], + "ignore": [ + "after-comment" + ] + } + ], + "unit-whitelist": [ + "em", + "rem", + "%", + "s", + "px" + ] + } + } +} diff --git a/webpack5/webpack.config.common.js b/webpack5/webpack.config.common.js new file mode 100644 index 0000000..e7dfcb7 --- /dev/null +++ b/webpack5/webpack.config.common.js @@ -0,0 +1,116 @@ +/* + * Common Environment + */ + +const webpack = require('webpack'); +const commonVariables = require('./webpack.configuration'); +const conf = commonVariables.configuration; + +const path = require('path'); +const filesystem = require('fs'); + +const UIInfo = require('./node_modules/@a2nt/ss-bootstrap-ui-webpack-boilerplate/package.json'); +const UINAME = JSON.stringify(UIInfo.name); +const UIVERSION = JSON.stringify(UIInfo.version); +console.info(`%cUI Kit ${UINAME} ${UIVERSION}`, 'color:yellow;font-size:14px'); + +const includes = {}; +const modules = [ + path.resolve(__dirname, conf.APPDIR, 'client', 'src'), + path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'js'), + path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'scss'), + path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'img'), + path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'thirdparty'), + path.resolve(__dirname, conf.APPDIR, 'client', 'node_modules'), + path.resolve(__dirname, 'node_modules'), + path.resolve(__dirname), + path.resolve(__dirname, 'public'), +]; + +const _addAppFiles = (theme) => { + const dirPath = path.resolve(__dirname, theme); + const themeName = path.basename(theme); + + if (filesystem.existsSync(path.join(dirPath, conf.SRC, 'js', 'app.js'))) { + includes[`${themeName}`] = path.join(dirPath, conf.SRC, 'js', 'app.js'); + } else if ( + filesystem.existsSync(path.join(dirPath, conf.SRC, 'scss', 'app.scss')) + ) { + includes[`${themeName}`] = path.join( + dirPath, + conf.SRC, + 'scss', + 'app.scss', + ); + } + + modules.push(path.join(dirPath, 'client', 'src', 'js')); + modules.push(path.join(dirPath, 'client', 'src', 'scss')); + modules.push(path.join(dirPath, 'client', 'src', 'img')); + modules.push(path.join(dirPath, 'client', 'src', 'thirdparty')); + + const _getAllFilesFromFolder = function (dir, includeSubFolders = true) { + const dirPath = path.resolve(__dirname, dir); + let results = []; + + filesystem.readdirSync(dirPath).forEach((file) => { + if (file.charAt(0) === '_') { + return; + } + + const filePath = path.join(dirPath, file); + const stat = filesystem.statSync(filePath); + + if (stat && stat.isDirectory() && includeSubFolders) { + results = results.concat( + _getAllFilesFromFolder(filePath, includeSubFolders), + ); + } else { + results.push(filePath); + } + }); + + return results; + }; + + // add page specific scripts + const typesJSPath = path.join(theme, conf.TYPESJS); + if (filesystem.existsSync(typesJSPath)) { + const pageScripts = _getAllFilesFromFolder(typesJSPath, true); + pageScripts.forEach((file) => { + includes[`${themeName}_${path.basename(file, '.js')}`] = file; + }); + } + + // add page specific scss + const typesSCSSPath = path.join(theme, conf.TYPESSCSS); + if (filesystem.existsSync(typesSCSSPath)) { + const scssIncludes = _getAllFilesFromFolder(typesSCSSPath, true); + scssIncludes.forEach((file) => { + includes[`${themeName}_${path.basename(file, '.scss')}`] = file; + }); + } +}; + +_addAppFiles(conf.APPDIR); + +// add themes +commonVariables.themes.forEach((theme) => { + _addAppFiles(theme); +}); + +module.exports = { + entry: includes, + externals: { + jquery: 'jQuery', + }, + resolve: { + modules: modules, + alias: { + 'window.jQuery': require.resolve('jquery'), + $: require.resolve('jquery'), + jquery: require.resolve('jquery'), + jQuery: require.resolve('jquery'), + }, + }, +}; diff --git a/webpack5/webpack.config.js b/webpack5/webpack.config.js new file mode 100644 index 0000000..5ab8cad --- /dev/null +++ b/webpack5/webpack.config.js @@ -0,0 +1,347 @@ +/* + * Production assets generation + */ +const COMPRESS = true; + +const webpack = require('webpack'); +const commonVariables = require('./webpack.configuration'); +const conf = commonVariables.configuration; +const { merge } = require('webpack-merge'); +const common = require('./webpack.config.common.js'); + +const filesystem = require('fs'); +const path = require('path'); + +//const FaviconsWebpackPlugin = require('favicons-webpack-plugin'); + +const TerserPlugin = require('terser-webpack-plugin'); +const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const ImageminPlugin = require('image-minimizer-webpack-plugin'); +const ImageSpritePlugin = require('@a2nt/image-sprite-webpack-plugin'); + +const UIInfo = require('./node_modules/@a2nt/ss-bootstrap-ui-webpack-boilerplate/package.json'); +const UIMetaInfo = require('./node_modules/@a2nt/meta-lightbox/package.json'); +const UIVERSION = JSON.stringify(UIInfo.version); + +console.log('WebP images: ' + conf['webp']); + +let plugins = [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + Popper: ['popper.js', 'default'], + Util: 'exports-loader?Util!bootstrap/js/dist/util', + Alert: 'exports-loader?Alert!bootstrap/js/dist/alert', + Button: 'exports-loader?Button!bootstrap/js/dist/button', + Carousel: 'exports-loader?Carousel!bootstrap/js/dist/carousel', + Collapse: 'exports-loader?Collapse!bootstrap/js/dist/collapse', + Dropdown: 'exports-loader?Dropdown!bootstrap/js/dist/dropdown', + Modal: 'exports-loader?Modal!bootstrap/js/dist/modal', + Tooltip: 'exports-loader?Tooltip!bootstrap/js/dist/tooltip', + Popover: 'exports-loader?Popover!bootstrap/js/dist/popover', + Scrollspy: 'exports-loader?Scrollspy!bootstrap/js/dist/scrollspy', + Tab: 'exports-loader?Tab!bootstrap/js/dist/tab', + }), + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify('production'), + }, + UINAME: JSON.stringify(UIInfo.name), + UIVERSION: UIVERSION, + UIAUTHOR: JSON.stringify(UIInfo.author), + UIMetaNAME: JSON.stringify(UIMetaInfo.name), + UIMetaVersion: JSON.stringify(UIMetaInfo.version), + }), + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false, + }), + new MiniCssExtractPlugin({ + filename: 'css/[name].css', + //allChunks: true, + }), + new OptimizeCssAssetsPlugin({ + //assetNameRegExp: /\.optimize\.css$/g, + cssProcessor: require('cssnano'), + cssProcessorPluginOptions: { + preset: ['default'], + }, + cssProcessorOptions: { + zindex: true, + cssDeclarationSorter: true, + reduceIdents: false, + mergeIdents: true, + mergeRules: true, + mergeLonghand: true, + discardUnused: true, + discardOverridden: true, + discardDuplicates: true, + discardComments: { + removeAll: true, + }, + }, + canPrint: true, + }), + require('autoprefixer'), + new ImageminPlugin({ + minimizerOptions: { + // Lossless optimization with custom option + // Feel free to experiment with options for better result for you + plugins: [ + ['gifsicle', { interlaced: true }], + ['jpegtran', { progressive: true }], + ['optipng', { optimizationLevel: 5 }], + [ + 'svgo', + { + plugins: [ + { + removeViewBox: false, + }, + ], + }, + ], + ], + }, + }), + new ImageSpritePlugin({ + exclude: /exclude|original|default-|icons|sprite/, + commentOrigin: false, + compress: COMPRESS, + extensions: ['png'], + indent: '', + log: true, + //outputPath: path.join(__dirname, conf.APPDIR, conf.DIST), + outputFilename: 'img/sprite-[hash].png', + padding: 0, + }), +]; + +/*const faviconPath = path.join(__dirname, conf.APPDIR, conf.SRC, 'favicon.png'); +if (filesystem.existsSync(faviconPath)) { + plugins.push( + new FaviconsWebpackPlugin({ + title: 'Webpack App', + logo: faviconPath, + prefix: '/icons/', + emitStats: false, + persistentCache: true, + inject: false, + statsFilename: path.join( + conf.APPDIR, + conf.DIST, + 'icons', + 'iconstats.json', + ), + icons: { + android: true, + appleIcon: true, + appleStartup: true, + coast: true, + favicons: true, + firefox: true, + opengraph: true, + twitter: true, + yandex: true, + windows: true, + }, + }), + ); +} + +// add themes favicons +commonVariables.themes.forEach((theme) => { + const faviconPath = path.join(__dirname, theme, conf.SRC, 'favicon.png'); + if (filesystem.existsSync(faviconPath)) { + plugins.push( + new FaviconsWebpackPlugin({ + title: 'Webpack App', + logo: faviconPath, + prefix: '/' + theme + '-icons/', + emitStats: false, + persistentCache: true, + inject: false, + statsFilename: path.join( + conf.APPDIR, + conf.DIST, + theme + '-icons', + 'iconstats.json', + ), + icons: { + android: true, + appleIcon: true, + appleStartup: true, + coast: true, + favicons: true, + firefox: true, + opengraph: true, + twitter: true, + yandex: true, + windows: true, + }, + }), + ); + } +});*/ + +const cfg = merge(common, { + mode: 'production', + cache: { + type: 'filesystem', + }, + recordsPath: path.join(__dirname, conf.APPDIR, conf.DIST, 'records.json'), + optimization: { + //removeAvailableModules: false, + //realContentHash: false, + splitChunks: { + name: 'vendor', + minChunks: 2, + }, + concatenateModules: true, //ModuleConcatenationPlugin + minimizer: [ + new TerserPlugin({ + terserOptions: { + module: false, + parse: { + // we want terser to parse ecma 8 code. However, we don't want it + // to apply any minfication steps that turns valid ecma 5 code + // into invalid ecma 5 code. This is why the 'compress' and 'output' + // sections only apply transformations that are ecma 5 safe + // https://github.com/facebook/create-react-app/pull/4234 + ecma: 8, + }, + compress: { + ecma: 5, + warnings: false, + // Disabled because of an issue with Uglify breaking seemingly valid code: + // https://github.com/facebook/create-react-app/issues/2376 + // Pending further investigation: + // https://github.com/mishoo/UglifyJS2/issues/2011 + comparisons: false, + }, + keep_fnames: true, + keep_classnames: true, + + mangle: { + safari10: true, + keep_fnames: true, + keep_classnames: true, + reserved: ['$', 'jQuery', 'jquery'], + }, + output: { + ecma: 5, + comments: false, + // Turned on because emoji and regex is not minified properly using default + // https://github.com/facebook/create-react-app/issues/2488 + ascii_only: true, + }, + }, + // Use multi-process parallel running to improve the build speed + // Default number of concurrent runs: os.cpus().length - 1 + parallel: true, + }), + ], + }, + + output: { + publicPath: path.join(conf.APPDIR, conf.DIST), + path: path.join(__dirname, conf.APPDIR, conf.DIST), + filename: path.join('js', '[name].js'), + }, + + module: { + rules: [ + { + test: /\.jsx?$/, + //exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], //Preset used for env setup + plugins: [['@babel/transform-react-jsx']], + cacheDirectory: true, + cacheCompression: true, + }, + }, + }, + { + test: /\.s?css$/, + use: [ + { + loader: MiniCssExtractPlugin.loader, + }, + { + loader: 'css-loader', + options: { + sourceMap: !COMPRESS, + }, + }, + { + loader: 'resolve-url-loader', + }, + { + loader: 'sass-loader', + options: { + sourceMap: !COMPRESS, + }, + }, + ], + }, + { + test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'fonts/', + publicPath: '../fonts/', + }, + }, + ], + }, + { + test: /\.(ttf|otf|eot|svg|woff(2)?)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'fonts/', + publicPath: '../fonts/', + }, + }, + ], + }, + { + test: /\.(png|webp|jpg|jpeg|gif|svg)$/, + use: [ + { + loader: 'img-optimize-loader', + options: { + name: '[name].[ext]', + outputPath: 'img/', + publicPath: '../img/', + compress: { + // This will take more time and get smaller images. + mode: 'low', // 'lossless', 'high', 'low' + disableOnDevelopment: true, + webp: conf['webp'], + }, + inline: { + limit: 1, + }, + }, + }, + ], + }, + ], + }, + + plugins: plugins, +}); + +console.log(cfg); +module.exports = cfg; diff --git a/webpack5/webpack.config.serve.js b/webpack5/webpack.config.serve.js new file mode 100644 index 0000000..de02cc9 --- /dev/null +++ b/webpack5/webpack.config.serve.js @@ -0,0 +1,154 @@ +/* + * Development assets generation + */ + +const COMPRESS = false; + +const path = require('path'); +//const autoprefixer = require('autoprefixer'); +const webpack = require('webpack'); +const { merge } = require('webpack-merge'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const common = require('./webpack.config.common.js'); +const commonVariables = require('./webpack.configuration'); +const conf = commonVariables.configuration; + +const IP = process.env.IP || conf.HOSTNAME; +const PORT = process.env.PORT || conf.PORT; + +const UIInfo = require('./node_modules/@a2nt/ss-bootstrap-ui-webpack-boilerplate/package.json'); +const UIMetaInfo = require('./node_modules/@a2nt/meta-lightbox/package.json'); + +const config = merge(common, { + mode: 'development', + + entry: { + hot: [ + 'react-hot-loader/patch', + 'webpack-dev-server/client?https://' + conf.HOSTNAME + ':' + conf.PORT, + 'webpack/hot/only-dev-server', + ], + }, + + output: { + path: path.join(__dirname), + filename: '[name].js', + // necessary for HMR to know where to load the hot update chunks + publicPath: 'https://' + conf.HOSTNAME + ':' + conf.PORT + '/', + }, + + module: { + rules: [ + { + test: /\.jsx?$/, + //exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], //Preset used for env setup + plugins: [['@babel/transform-react-jsx']], + cacheDirectory: true, + cacheCompression: false, + }, + }, + }, + { + test: /\.s?css$/, + use: [ + { + loader: MiniCssExtractPlugin.loader, + }, + { + loader: 'css-loader', + options: { + sourceMap: !COMPRESS, + }, + }, + { + loader: 'resolve-url-loader', + }, + { + loader: 'sass-loader', + options: { + sourceMap: false, + }, + }, + ], + }, + { + test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, + use: [ + { + loader: 'url-loader', + }, + ], + }, + { + test: /\.(gif|png|jpg|jpeg|ttf|otf|eot|svg|webp|woff(2)?)$/, + use: [ + { + loader: 'file-loader', + options: { + name(file) { + return 'public/[path][name].[ext]'; + }, + }, + }, + ], + }, + ], + }, + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery', + Popper: ['popper.js', 'default'], + Util: 'exports-loader?Util!bootstrap/js/dist/util', + Alert: 'exports-loader?Alert!bootstrap/js/dist/alert', + Button: 'exports-loader?Button!bootstrap/js/dist/button', + Carousel: 'exports-loader?Carousel!bootstrap/js/dist/carousel', + Collapse: 'exports-loader?Collapse!bootstrap/js/dist/collapse', + Dropdown: 'exports-loader?Dropdown!bootstrap/js/dist/dropdown', + Modal: 'exports-loader?Modal!bootstrap/js/dist/modal', + Tooltip: 'exports-loader?Tooltip!bootstrap/js/dist/tooltip', + Popover: 'exports-loader?Popover!bootstrap/js/dist/popover', + Scrollspy: 'exports-loader?Scrollspy!bootstrap/js/dist/scrollspy', + Tab: 'exports-loader?Tab!bootstrap/js/dist/tab', + }), + new webpack.HotModuleReplacementPlugin(), + new webpack.DefinePlugin({ + UINAME: JSON.stringify(UIInfo.name), + UIVERSION: JSON.stringify(UIInfo.version), + UIAUTHOR: JSON.stringify(UIInfo.author), + UIMetaNAME: JSON.stringify(UIMetaInfo.name), + UIMetaVersion: JSON.stringify(UIMetaInfo.version), + }), + ], + + devServer: { + host: IP, + port: PORT, + historyApiFallback: true, + //hot: true, + /*clientLogLevel: 'info', + disableHostCheck: true, + contentBase: [ + path.resolve(__dirname, 'public'), + path.resolve(__dirname, 'public', 'resources'), + path.resolve(__dirname, 'public', 'resources', conf.APPDIR, conf.DIST), + 'node_modules', + ],*/ + //watchContentBase: true, + overlay: { + warnings: true, + errors: true, + }, + headers: { + 'Access-Control-Allow-Origin': '*', + }, + }, +}); + +module.exports = config; diff --git a/webpack5/webpack.configuration.js b/webpack5/webpack.configuration.js new file mode 100644 index 0000000..505ab6c --- /dev/null +++ b/webpack5/webpack.configuration.js @@ -0,0 +1,33 @@ +/* + * Load webpack configuration from app/_config/webpack.yml + */ + +const path = require('path'); +const filesystem = require('fs'); +const fs = require('fs'); +const yaml = require('js-yaml'); + +const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, 'app/_config/webpack.yml'), 'utf8')); + +let themes = []; +// add themes +if (conf['Site\\Templates\\WebpackTemplateProvider'].THEMESDIR) { + const themeDir = conf['Site\\Templates\\WebpackTemplateProvider'].THEMESDIR; + const dir = path.resolve(__dirname, themeDir); + + if (filesystem.existsSync(dir)) { + filesystem.readdirSync(dir).forEach((file) => { + filePath = path.join(themeDir, file); + const stat = filesystem.statSync(filePath); + + if (stat && stat.isDirectory()) { + themes.push(filePath); + } + }); + } +} + +module.exports = { + configuration: conf['Site\\Templates\\WebpackTemplateProvider'], + themes: themes, +};