cheetah-framework
Version:
Cheetah Framework JS used in all our applications
205 lines (170 loc) • 6.2 kB
JavaScript
const path = require('path')
const mix = require('laravel-mix')
const { argv } = require('yargs')
const Paths = require('./Paths')
const Config = require('./Config')
const File = require('./File')
const glob = require('glob')
const fs = require('fs-extra')
global.path = path
// make it extend cheetah class
class Cheetah {
constructor (rootPath) {
rootPath = rootPath || process.cwd()
this.argv = argv
this.config = new Config(rootPath)
this.paths = new Paths(rootPath, this)
this.moduleAlias = {}
this.relativeModuleAlias = {}
this.scssModules = []
this.modulesFonts = []
this.modulesImages = []
this.modules = []
}
start () {
this.loadModules()
this.writeSassFile()
this.mix()
}
/**
* Create aliases + build main sass file
*/
loadModules () {
// remove existing symlinks
if (File.exists(this.paths.symlinkFolder)) {
fs.readdirSync(this.paths.symlinkFolder, { withFileTypes: true }).forEach(file => {
if (file.isSymbolicLink()) {
fs.unlinkSync(this.paths.symlinkFolder + '/' + file.name)
}
})
} else {
console.error('Missing folder: ' + this.paths.symlinkFolder)
process.exit()
}
this.modules = this.config.modules
this.modules.push(this.paths.appPath)
this.modules.unshift(path.resolve(__dirname, '..'))
this.modules.forEach(module => {
const configPath = module + '/.cheetah.js'
if (!File.exists(configPath)) {
throw new Error('Missing .cheetah.js file in ' + module)
}
this.loadModule(configPath)
// Sub modules
glob.sync(module + '/js/modules/*/.cheetah.js', {}).forEach(module => this.loadModule(module))
})
}
loadModule (configPath) {
const folder = path.relative(this.paths.rootPath, path.dirname(configPath))
const scssFile = path.dirname(configPath) + '/sass/_main.scss'
const config = require(configPath)
// Add alias and symlink on @moduleName
if (config.moduleName) {
const jsFolder = File.exists(`${folder}/js`) ? `${folder}/js` : folder
// prevent infinite symlink recursion
if (!this.paths.root(jsFolder).includes(this.paths.appPath)) {
fs.symlinkSync(this.paths.root(jsFolder), `${this.paths.symlinkFolder}/${config.moduleName}`)
}
this.moduleAlias[config.moduleName.replace('@', '@@')] = this.paths.root(jsFolder)
this.relativeModuleAlias[config.moduleName] = jsFolder
if (File.exists(`${folder}/images`)) {
this.modulesImages.push(`${folder}/images`)
}
if (File.exists(`${folder}/fonts`)) {
this.modulesFonts.push(`${folder}/fonts`)
}
}
if (config.sassAutoload !== false && File.exists(scssFile)) {
if (config.sassFirst === true) {
this.scssModules.unshift(scssFile)
} else {
this.scssModules.push(scssFile)
}
}
if (config.alias) {
Object.keys(config.alias).forEach(aliasName => {
this.moduleAlias[aliasName.replace('@', '@@')] = this.paths.root(folder + '/' + config.alias[aliasName])
this.relativeModuleAlias[aliasName] = folder + '/' + config.alias[aliasName]
})
}
}
writeSassFile () {
const file = new File(`${this.paths.appPath}/sass/app.scss`)
let content = `
/*****
* Cheetah auto generated file
* DO NOT EDIT/DELETE
**/\n\n`
// Load framework variables
const frameworkVariableFile = this.paths.relative(path.resolve(__dirname, '..') + '/sass/_variables.scss')
content += ` "${frameworkVariableFile}";\n`
// Project variables
if (File.exists(`${this.paths.appPath}/sass/_variables.scss`)) {
content += '@import "_variables";\n'
}
this.scssModules.forEach(module => {
content += ` "${this.paths.relative(module)}";\n`
})
file.write(content)
}
mix () {
const _this = this
const modulePaths = this.modules.reverse().map(path => (File.exists(`${path}/js`) ? `${path}/js` : path) + '/')
modulePaths.pop() // remove cheetah framework path
const relativeModulePaths = modulePaths.map(path => this.paths.relative(path))
for (const key in _this.relativeModuleAlias) {
const path = _this.relativeModuleAlias[key]
// find modulePath matching start of alias path
const match = relativeModulePaths.find(replacePath => replacePath === path.slice(0, replacePath.length))
if (match) {
_this.relativeModuleAlias[key] = path.slice(match.length)
}
}
mix.webpackConfig(function (env, argv) {
return {
resolve: {
mainFiles: ['index', 'Index'],
modules: [
...modulePaths,
_this.paths.root(),
'node_modules',
],
alias: {
..._this.moduleAlias,
..._this.relativeModuleAlias
}
},
output: {
chunkFilename: 'cheetah/js/chunks/[name].[chunkhash].js'
}
}
})
if (!mix.inProduction() && process.env.MIX_SOURCEMAPS === 'true') {
mix.sourceMaps()
}
mix.options({
processCssUrls: false
})
mix.js(`${this.paths.appPath}/js/app.js`, 'public/cheetah/js')
.sass(`${this.paths.appPath}/sass/app.scss`, 'public/cheetah/css').version()
// Copy assets
mix.copy([path.resolve(__dirname, '../fonts'), ...this.modulesFonts], 'public/cheetah/fonts')
mix.copy([path.resolve(__dirname, '../images'), ...this.modulesImages], 'public/cheetah/images')
mix.copy(path.resolve(this.paths.rootPath, 'node_modules/element-ui/lib/theme-chalk/fonts'), 'public/cheetah/css/fonts')
/**
* Locate and override laravel-mix js Webpack rule
* @todo - Should be update in TROC-2472 Pre compile cheetah framework
*/
mix.override((webpackConfig) => {
const jsRule = webpackConfig.module.rules.find(rule => {
return rule.test.toString() === /\.jsx?$/.toString()
})
if (!jsRule) {
console.error('ERROR - Unable to locate laravel-mix js Webpack rule')
process.exit()
}
jsRule.exclude = /node_modules\/(?!(cheetah-framework|)\/).*/
})
}
}
module.exports = Cheetah