UNPKG

lincd-cli

Version:

Command line tools for the lincd.js library

495 lines 22.1 kB
"use strict"; 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