diff --git a/commands/Mix/Base.ts b/commands/Mix/Base.ts new file mode 100644 index 0000000..982d95b --- /dev/null +++ b/commands/Mix/Base.ts @@ -0,0 +1,62 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { BaseCommand } from '@adonisjs/ace' +import { flags } from '@adonisjs/core/build/standalone' +import { spawn } from 'child_process' + +/** + * Base class to provide helpers for Mix commands + */ +export abstract class BaseMix extends BaseCommand { + @flags.string({ + description: "The path to your Mix configuration file. Default: 'webpack.mix.js'", + }) + public mixConfig = 'webpack.mix.js' + + @flags.boolean({ description: 'Enable progress reporting. Default: true' }) + public progress = true + + protected get isTesting() { + return process.env.TESTING + } + + protected get isTTY() { + if (this.isTesting && process.env.IS_TTY !== undefined) { + return process.env.IS_TTY === 'true' + } + + if (this.isTesting && process.stdout.isTTY === undefined) { + return true + } + + return process.stdout.isTTY + } + + protected runScript(script: string, scriptEnv: NodeJS.ProcessEnv) { + if (this.isTesting) { + process.stdout.write(JSON.stringify({ script, env: scriptEnv })) + return + } + + const child = spawn(script, { + stdio: 'inherit', + shell: true, + env: { ...process.env, ...scriptEnv }, + }) + + child.on('exit', (code, signal) => { + if (code === null) { + code = signal === 'SIGINT' ? 130 : 1 + } + + process.exitCode = code + }) + } +} diff --git a/commands/Mix/Build.ts b/commands/Mix/Build.ts index 3bb15b9..e7a2aac 100644 --- a/commands/Mix/Build.ts +++ b/commands/Mix/Build.ts @@ -1,87 +1,58 @@ -import { BaseCommand, flags } from '@adonisjs/core/build/standalone' -import { spawn } from 'child_process' +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { flags } from '@adonisjs/core/build/standalone' import { existsSync } from 'fs' -import { join } from 'path' - -export default class MixBuild extends BaseCommand { +import { relative } from 'path' +import { BaseMix } from './Base' + +/** + * Command to build assets + * + * Reference: https://github.com/JeffreyWay/laravel-mix/blob/8cfacdde47/bin/cli.js + */ +export default class MixBuild extends BaseMix { public static commandName = 'mix:build' public static description = 'Compile Mix' public static settings = { stayAlive: true, } - @flags.boolean({ description: 'Build assets for production', default: false }) + @flags.boolean({ description: 'Build assets for production' }) public production: boolean - @flags.boolean({ - description: 'Open bundle analyzer', - default: false, - }) + @flags.boolean({ description: 'Open bundle analyzer' }) public analyze: boolean - @flags.string({ - description: - "The path to your Mix configuration file. The default is your root 'webpack.mix.js'", - default: 'webpack.mix.js', - }) - public mixConfig: string - public async run() { - let webpackConfigPath = require.resolve('laravel-mix/setup/webpack.config.js') - if (!existsSync(webpackConfigPath)) { - this.logger.error('Please install Laravel Mix') - return - } - - if (this.analyze) { - webpackConfigPath = require.resolve('../../setup/webpack.config.js') - } - - const mixConfigPath = join(this.application.cliCwd!, this.mixConfig) + const mixConfigPath = this.application.makePath(this.mixConfig) if (!existsSync(mixConfigPath)) { this.logger.error(`The Mix configuration file '${this.mixConfig}' is not found`) return } let commandScript: string - if (this.isTTY()) commandScript = 'npx webpack --progress' + if (this.isTTY && this.progress) commandScript = 'npx webpack --progress' else commandScript = 'npx webpack' - const script = [ - `npx cross-env NODE_ENV=${this.production ? 'production' : 'development'}`, - `MIX_FILE=${this.mixConfig}`, - commandScript, - `--config=${webpackConfigPath}`, - ].join(' ') + let configPath = 'laravel-mix/setup/webpack.config.js' + if (this.analyze) configPath = '../../setup/webpack.config.js' - if (this.isTesting()) { - process.stdout.write(script) - return - } - - const child = spawn(script, { - stdio: 'inherit', - shell: true, - }) - - child.on('exit', (code) => { - if (code) process.exitCode = code - }) - } + const webpackConfigPath = relative(this.application.appRoot, require.resolve(configPath)) - private isTesting() { - return process.env.TESTING - } - - private isTTY() { - if (this.isTesting() && process.env.IS_TTY !== undefined) { - return process.env.IS_TTY === 'true' - } + const script = [commandScript, `--config="${webpackConfigPath}"`].join(' ') - if (this.isTesting() && process.stdout.isTTY === undefined) { - return true + const scriptEnv = { + NODE_ENV: this.production ? 'production' : 'development', + MIX_FILE: this.mixConfig, } - return process.stdout.isTTY + this.runScript(script, scriptEnv) } } diff --git a/commands/Mix/Watch.ts b/commands/Mix/Watch.ts index 264160a..ba07356 100644 --- a/commands/Mix/Watch.ts +++ b/commands/Mix/Watch.ts @@ -1,80 +1,62 @@ -import { BaseCommand, flags } from '@adonisjs/core/build/standalone' -import { spawn } from 'child_process' +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { flags } from '@adonisjs/core/build/standalone' import { existsSync } from 'fs' -import { join } from 'path' - -export default class MixWatch extends BaseCommand { +import { relative } from 'path' +import { BaseMix } from './Base' + +/** + * Command to watch assets + * + * Reference: https://github.com/JeffreyWay/laravel-mix/blob/8cfacdde47/bin/cli.js + */ +export default class MixWatch extends BaseMix { public static commandName = 'mix:watch' public static description = 'Build and watch files for changes' public static settings = { stayAlive: true, } - @flags.boolean({ description: 'Enable hot reloading', default: false }) + @flags.boolean({ description: 'Enable hot reloading' }) public hot: boolean - @flags.string({ - description: - "The path to your Mix configuration file. The default is your root 'webpack.mix.js'", - default: 'webpack.mix.js', - }) - public mixConfig: string + @flags.boolean({ description: 'Enable https' }) + public https: boolean public async run() { - const webpackConfigPath = require.resolve('laravel-mix/setup/webpack.config.js') - if (!existsSync(webpackConfigPath)) { - this.logger.error('Please install Laravel Mix') - return - } - - const mixConfigPath = join(this.application.cliCwd!, this.mixConfig) + const mixConfigPath = this.application.makePath(this.mixConfig) if (!existsSync(mixConfigPath)) { this.logger.error(`The Mix configuration file '${this.mixConfig}' is not found`) return } let commandScript: string - if (this.hot) commandScript = 'npx webpack serve --hot' - else { - if (this.isTTY()) commandScript = 'npx webpack --progress --watch' + if (!this.hot) { + if (this.isTTY && this.progress) commandScript = 'npx webpack --progress --watch' else commandScript = 'npx webpack --watch' + } else { + commandScript = 'npx webpack serve --hot' + (this.https ? ' --https' : '') } - const script = [ - 'npx cross-env NODE_ENV=development', - `MIX_FILE=${this.mixConfig}`, - commandScript, - `--config=${webpackConfigPath}`, - ].join(' ') - - if (this.isTesting()) { - process.stdout.write(script) - return - } + const webpackConfigPath = relative( + this.application.appRoot, + require.resolve('laravel-mix/setup/webpack.config.js') + ) - const child = spawn(script, { - stdio: 'inherit', - shell: true, - }) - - child.on('exit', (code) => { - if (code) process.exitCode = code - }) - } - - private isTesting() { - return process.env.TESTING - } - - private isTTY() { - if (this.isTesting() && process.env.IS_TTY !== undefined) { - return process.env.IS_TTY === 'true' - } + const script = [commandScript, `--config="${webpackConfigPath}"`].join(' ') - if (this.isTesting() && process.stdout.isTTY === undefined) { - return true + const scriptEnv = { + NODE_ENV: 'development', + MIX_FILE: this.mixConfig, } - return process.stdout.isTTY + this.runScript(script, scriptEnv) } } diff --git a/commands/index.ts b/commands/index.ts index fc3fccf..020bee7 100644 --- a/commands/index.ts +++ b/commands/index.ts @@ -1,3 +1,12 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + export default [ 'adonis-mix-asset/build/commands/Mix/Build', 'adonis-mix-asset/build/commands/Mix/Watch', diff --git a/instructions.ts b/instructions.ts index e5694d5..0930974 100644 --- a/instructions.ts +++ b/instructions.ts @@ -1,3 +1,12 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import * as sinkStatic from '@adonisjs/sink' import { ApplicationContract } from '@ioc:Adonis/Core/Application' import { join } from 'path' diff --git a/providers/MixAssetProvider.ts b/providers/MixAssetProvider.ts index 4ac9fc1..793963c 100644 --- a/providers/MixAssetProvider.ts +++ b/providers/MixAssetProvider.ts @@ -1,15 +1,18 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { ApplicationContract } from '@ioc:Adonis/Core/Application' -import { ViewContract } from '@ioc:Adonis/Core/View' import { existsSync, readFileSync } from 'fs' import { mixAsset } from '../src/mixAsset' export default class MixAssetProvider { constructor(protected app: ApplicationContract) {} - public static needsApplication = true - - public register() { - // Register your own bindings - } /** * Returns the manifest file contents. During development, we make use of the @@ -24,22 +27,12 @@ export default class MixAssetProvider { } public boot() { - // IoC container is ready - this.app.container.with(['Adonis/Core/View'], (view: ViewContract) => { - const manifestPath = this.app.publicPath('mix-manifest.json') - if (existsSync(manifestPath)) { - view.global('mix', (path: string) => - mixAsset(this.app, this.getManifestContents(manifestPath), path) - ) - } - }) - } - - public shutdown() { - // Cleanup, since app is going down - } - - public ready() { - // App is ready + const View = this.app.container.resolveBinding('Adonis/Core/View') + const manifestPath = this.app.publicPath('mix-manifest.json') + if (existsSync(manifestPath)) { + View.global('mix', (path: string) => + mixAsset(this.app, this.getManifestContents(manifestPath), path) + ) + } } } diff --git a/setup/webpack.config.ts b/setup/webpack.config.ts index 379aee6..75e77db 100644 --- a/setup/webpack.config.ts +++ b/setup/webpack.config.ts @@ -1,3 +1,12 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import type { Configuration } from 'webpack' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' diff --git a/src/mixAsset.ts b/src/mixAsset.ts index d56d5cc..3b37822 100644 --- a/src/mixAsset.ts +++ b/src/mixAsset.ts @@ -1,7 +1,16 @@ +/* + * adonis-mix-asset + * + * (c) Wahyu Budi Saputra + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { ApplicationContract } from '@ioc:Adonis/Core/Application' import { existsSync, readFileSync } from 'fs' -// Reference: https://github.com/laravel/framework/blob/8.x/src/Illuminate/Foundation/Mix.php +// Reference: https://github.com/laravel/framework/blob/990e0e7/src/Illuminate/Foundation/Mix.php export function mixAsset( application: ApplicationContract, manifest: Record, @@ -15,7 +24,7 @@ export function mixAsset( const url = readFileSync(application.publicPath('hot'), 'utf-8').trim() if (url.startsWith('http://') || url.startsWith('https://')) { - return url.substring(url.indexOf(':') + 1, url.lastIndexOf('/')) + path + return url.substring(url.indexOf(':') + 1) + path } return '//localhost:8080' + path diff --git a/tsconfig.json b/tsconfig.json index 34ef00a..d96d1a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "experimentalDecorators": true, "skipLibCheck": true, - "types": ["@types/node", "@adonisjs/core", "@adonisjs/view"] + "types": ["@adonisjs/core", "@adonisjs/view"] } }