lincd-cli
Version:
Command line tools for the lincd.js library
495 lines • 22.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWebpackAppConfig = exports.getLincdConfig = void 0;
const path_1 = __importDefault(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const react_refresh_typescript_1 = __importDefault(require("react-refresh-typescript"));
const react_refresh_webpack_plugin_1 = __importDefault(require("@pmmmwh/react-refresh-webpack-plugin"));
const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
const webpack_1 = __importDefault(require("webpack"));
const fs_1 = __importDefault(require("fs"));
const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
const terser_webpack_plugin_1 = __importDefault(require("terser-webpack-plugin"));
const utils_js_1 = require("./utils.js");
const LinkedFileStorage_1 = require("lincd/utils/LinkedFileStorage");
const postcss_url_1 = __importDefault(require("postcss-url"));
// import { addLincdSourcesPlugin } from './plugins/lincd-tailwind-sources';
const isProduction = process.env.NODE_ENV === 'production';
const isDevelopment = process.env.NODE_ENV === 'development';
const packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(process.cwd(), 'package.json'), 'utf-8'));
const cssModes = ['scss-modules', 'tailwind', 'scss', 'mixed'];
class WatchRunPlugin {
apply(compiler) {
compiler.hooks.watchRun.tap('watchRun', (comp) => {
if (comp.modifiedFiles) {
const changedFiles = Array.from(comp.modifiedFiles);
console.log(chalk_1.default.magenta('Changed files sorted by \'modified time\' stamps:'));
const entriesToCheck = [];
changedFiles.forEach((file) => {
try {
const stat = fs_1.default.statSync(file.toString());
console.log(` ${chalk_1.default.magenta(file)}`);
entriesToCheck.push({ path: file, mtime: stat.mtime });
if (stat.isDirectory()) {
const contents = fs_1.default.readdirSync(file.toString());
contents.forEach((name) => {
const fullPath = path_1.default.join(file.toString(), name);
try {
const innerStat = fs_1.default.statSync(fullPath);
//if less than 2 minutes ago...
if (innerStat.mtime > new Date(Date.now() - 2 * 60 * 1000)) {
entriesToCheck.push({ path: fullPath, mtime: innerStat.mtime });
}
}
catch (e) {
entriesToCheck.push({ path: fullPath, mtime: new Date(0), error: e.message });
}
});
}
}
catch (err) {
entriesToCheck.push({ path: file, mtime: new Date(0), error: err.message });
}
});
entriesToCheck
.sort((a, b) => b.mtime - a.mtime)
.splice(0, 3)
.forEach((entry) => {
const label = entry.error
? `[error: ${entry.error}]`
: `[${entry.mtime.toISOString()}]`;
console.log(` ${entry.path} ${label}`);
});
}
});
}
}
/**
* Converts a css class name to a unique scoped name (for CSS Modules)
* @param context
* @param currentFormat
* @param name
*/
function getLocalIdent(context, currentFormat, name) {
return isProduction ? (0, utils_js_1.generateScopedNameProduction)(name, context.resourcePath) : (0, utils_js_1.generateScopedName)(name, context.resourcePath);
}
const getLincdConfig = async () => {
const lincdConfigPathJs = path_1.default.resolve(process.cwd(), 'lincd.config.js');
const lincdConfigPathJson = path_1.default.resolve(process.cwd(), 'lincd.config.json');
//default config
let config = {
//scss-modules is default
cssMode: cssModes[0],
analyse: false,
};
//overwriting config from package.json.lincdApp or lincd.config.js(on) file
if (typeof packageJson.lincdApp === 'object') {
//overwrite default with anything that's defined in lincdApp in package.json
config = { ...config, ...packageJson.lincdApp };
}
else if (fs_1.default.existsSync(lincdConfigPathJs)) {
let lincdConfig = await Promise.resolve(`${lincdConfigPathJs}`).then(s => __importStar(require(s)));
config = { ...config, ...lincdConfig.default };
}
else if (fs_1.default.existsSync(lincdConfigPathJson)) {
let lincdConfig = JSON.parse(fs_1.default.readFileSync(lincdConfigPathJson, 'utf-8'));
config = { ...config, ...lincdConfig };
}
if (!cssModes.includes(config.cssMode)) {
console.warn('Invalid value for property cssMode. Should be one of: ' +
cssModes.join(', '));
process.exit();
}
return config;
};
exports.getLincdConfig = getLincdConfig;
const getWebpackAppConfig = async () => {
// set up the storage config for the app
await Promise.resolve(`${path_1.default.join(process.cwd(), 'scripts', 'storage-config.js')}`).then(s => __importStar(require(s)));
const accessURL = LinkedFileStorage_1.LinkedFileStorage.accessURL;
// set up the public path for the app
// This should match the use of express.static() in LincdServer.tsx, which makes the build files available through a URL
const publicPath = '/public';
const bundlesPath = publicPath + '/bundles/';
// ASSET_PATH is used load the assets from the correct path
const ASSET_PATH = process.env.ASSET_PATH || accessURL ? accessURL + bundlesPath : bundlesPath;
let config = await (0, exports.getLincdConfig)();
let postcssPlugins = [];
//tailwind first (so its processed last and doesn't overwrite custom CSS modules)
if (config.cssMode === 'tailwind' || config.cssMode === 'mixed') {
//make sure that tailwind classes from any LINCD packages that are listed in package.json:dependencies are included
let lincdPackagePaths = (0, utils_js_1.getLINCDDependencies)(packageJson);
lincdPackagePaths = lincdPackagePaths.map(([packageName, packagePath]) => {
return packagePath + '/lib/**/*.{js,mjs}';
});
// console.log(
// chalk.blueBright('tailwind content: ') + chalk.magenta(['./frontend/src/**/*.{tsx,ts}', ...lincdPackagePaths]),
// );
postcssPlugins.push([
'@tailwindcss/postcss',
{
content: {
files: [
(process.env.SOURCE_PATH || './src/') + '**/*.{js}',
// ...lincdPackagePaths,
]
},
// config: {
// content: {
// files:[
// (process.env.SOURCE_PATH || './src/') + '**/*.{tsx,ts}',
// ...lincdPackagePaths,
// ]
// },
// // plugins:[
// // addLincdSourcesPlugin(),
// // ]
// },
// content: [
// (process.env.SOURCE_PATH || './src/') + '**/*.{tsx,ts}',
// ...lincdPackagePaths,
// ],
// safelist: isProduction
// ? {}
// : {
// //in development mode we allow all classes here, so that you can easily develop
// pattern: /./,
// variants: ['sm','md','lg','xl','2xl'],
// },
// features: {
// themeVariables: {
// generateAll: true,
// },
// },
// theme: {
// extend: {
// colors: getLinkedTailwindColors(),
// },
// },
plugins: [
// plugin(function({ addBase, theme }) {
//add styles to the base styles
//this replicates the preflight settings of tailwind v4, but without the destructive/strict #/# selectors
// addBase({
// // Reset all elements except common inline tags and semantic containers
// '*:not(code):not(pre):not(kbd):not(samp):not(mark):not(q):not(ins):not(del):not(span):not(a):not(b):not(i):not(em):not(u):not(s):not(small):not(strong):not(sub):not(sup), ::before, ::after': {
// boxSizing: 'border-box',
// margin: '0',
// padding: '0',
// borderWidth: '0',
// borderStyle: 'solid',
// borderColor: 'currentColor',
// },
// html: {
// lineHeight: '1.5',
// textSizeAdjust: '100%',
// WebkitTextSizeAdjust: '100%',
// MozTextSizeAdjust: '100%',
// fontFamily: 'system-ui, sans-serif',
// },
// body: {
// margin: '0',
// lineHeight: 'inherit',
// backgroundColor: 'white',
// },
// hr: {
// height: '0',
// color: 'inherit',
// borderTopWidth: '1px',
// },
// abbr: {
// textDecoration: 'underline dotted',
// },
// 'b, strong': {
// fontWeight: 'bolder',
// },
// 'code, kbd, samp, pre': {
// fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
// fontSize: '1em',
// },
// small: {
// fontSize: '80%',
// },
// 'sub, sup': {
// fontSize: '75%',
// lineHeight: '0',
// position: 'relative',
// verticalAlign: 'baseline',
// },
// sub: { bottom: '-0.25em' },
// sup: { top: '-0.5em' },
// table: {
// textIndent: '0',
// borderColor: 'inherit',
// borderCollapse: 'collapse',
// },
// 'button, input, optgroup, select, textarea': {
// font: 'inherit',
// color: 'inherit',
// margin: '0',
// padding: '0',
// lineHeight: 'inherit',
// backgroundColor: 'transparent',
// borderColor: 'inherit',
// },
// 'button, select': {
// textTransform: 'none',
// },
// 'button, [type="button"], [type="reset"], [type="submit"]': {
// appearance: 'button',
// WebkitAppearance: 'button',
// },
// '::-moz-focus-inner': {
// borderStyle: 'none',
// padding: '0',
// },
// ':-moz-focusring': {
// outline: 'auto',
// },
// ':-moz-ui-invalid': {
// boxShadow: 'none',
// },
// fieldset: {
// margin: '0',
// padding: '0',
// border: '0',
// },
// legend: {
// padding: '0',
// },
// });
// }),
],
// plugins: [
// tailwindPlugin(function({ addBase,config }) {
// //we can use LINCD CSS variables for default font color, size etc.
// // addBase({
// // 'h1': { fontSize: config('theme.fontSize.2xl') },
// // 'h2': { fontSize: config('theme.fontSize.xl') },
// // 'h3': { fontSize: config('theme.fontSize.lg') },
// // })
// }),
// ],
},
]);
}
else {
//if not using tailwind, then we use postcss-nested to enable nesting of css
postcssPlugins.push(['postcss-import', {}], ['postcss-preset-env', {
features: { 'nesting-rules': true },
}]);
}
//Add plugin which converts URLs in CSS to the correct FULL absolute path
postcssPlugins.push([
(0, postcss_url_1.default)({
url: (asset) => {
//TODO: for assets of packages, we want to detect the package path and resolve through node_modules/package-name/...something/assets
if (!asset.url.startsWith('data:')) {
// console.log('Transform CSS URL:'+asset.url);
return `${accessURL}${publicPath}${asset.url}`;
}
return asset.url;
},
}),
]);
if (config.cssMode === 'scss-modules' ||
config.cssMode === 'scss' ||
config.cssMode === 'mixed') {
postcssPlugins = postcssPlugins.concat([
// ['stylelint', {
// 'extends': [
// 'stylelint-config-standard'
// ],
// 'plugins': ['stylelint-scss'],
// 'rules': {
// 'at-rule-no-unknown': null,
// 'scss/at-rule-no-unknown': [
// true,
// {
// ignoreAtRules: [
// 'tailwind',
// 'apply',
// 'variants',
// 'responsive',
// 'screen',
// ],
// },
// ],
// 'no-descending-specificity': null,
// 'at-rule-empty-line-before':null,
// 'rule-empty-line-before': null,
// 'no-missing-end-of-source-newline': null,
// 'max-line-length': null,
// 'color-function-notation': null,
// 'alpha-value-notation': null,
// 'number-max-precision':null,
// },
// }],
isProduction && 'cssnano',
// "postcss-reporter",
]);
}
return {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
entry: [
isDevelopment && 'webpack-hot-middleware/client',
path_1.default.resolve(process.cwd(), process.env.ENTRY_PATH ||
(process.env.SOURCE_PATH
? process.env.SOURCE_PATH + '/index.tsx'
: './src/index.tsx')),
].filter(Boolean),
watch: isDevelopment || config.analyse,
output: {
path: path_1.default.resolve(process.cwd(), process.env.OUTPUT_PATH || './public/bundles'),
filename: '[name].bundle.js',
publicPath: ASSET_PATH,
clean: true,
},
watchOptions: {
//ignore everything except the src folder. ignore specific files in the src folder
ignored: /(^((?!src).)*$|\.d\.ts$|\.js\.map$|\.scss\.json$|node_modules|public|\.idea|[/\\]\..*)/,
aggregateTimeout: 500,
},
devServer: {
client: {
progress: false,
},
},
plugins: [
// new WatchRunPlugin(),
new mini_css_extract_plugin_1.default({
ignoreOrder: true
}),
new webpack_1.default.EnvironmentPlugin(Object.keys(process.env)),
isDevelopment && new react_refresh_webpack_plugin_1.default(),
isDevelopment && new webpack_1.default.HotModuleReplacementPlugin(),
config.analyse && new webpack_bundle_analyzer_1.BundleAnalyzerPlugin(),
...(Array.isArray(config.plugins) ? config.plugins : []),
].filter(Boolean),
externals: config.externals || {},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [
mini_css_extract_plugin_1.default.loader,
{
loader: 'css-loader',
options: {
url: false,
importLoaders: 1,
modules: {
mode: 'local',
getLocalIdent: getLocalIdent,
auto: (resourcePath) => {
//make sure this only applies to .module.css files, and not to tailwind
return /\.module\.css$/i.test(resourcePath) && !/tailwind/i.test(resourcePath);
}
},
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: postcssPlugins,
},
},
},
],
},
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader?' +
JSON.stringify({
compilerOptions: {
//this is required for dynamic imports & code splitting
module: 'esnext',
moduleResolution: 'node',
sourceMap: isDevelopment,
plugins: [{ 'name': 'typescript-plugin-css-modules' }],
},
}),
options: {
...(isDevelopment
? {
getCustomTransformers: () => ({
before: [(0, react_refresh_typescript_1.default)()],
}),
}
: {}),
transpileOnly: isProduction,
},
},
],
exclude: /node_modules/,
},
],
},
optimization: {
minimize: isProduction,
minimizer: [
new terser_webpack_plugin_1.default({
terserOptions: {
keep_classnames: true,
},
}),
],
},
stats: {
chunks: false,
assets: true,
entrypoints: false,
children: true,
modules: false,
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.css', '.scss', '.json'],
alias: config.alias || {},
},
//Cache is now overwritten in LincdServer based on config, the other value for type would be 'filesystem'
//see also https://webpack.js.org/configuration/other-options/#cache
cache: { type: 'memory' },
};
};
exports.getWebpackAppConfig = getWebpackAppConfig;
//# sourceMappingURL=config-webpack-app.js.map