├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── COMMIT_CONVENTION.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .npmrc ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── commands ├── Mix │ ├── Base.ts │ ├── Build.ts │ └── Watch.ts └── index.ts ├── config.json ├── instructions.ts ├── japaFile.js ├── package-lock.json ├── package.json ├── providers └── MixAssetProvider.ts ├── setup └── webpack.config.ts ├── src └── mixAsset.ts ├── templates └── webpack.mix.txt └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.json] 12 | insert_final_newline = ignore 13 | 14 | [**.min.js] 15 | indent_style = ignore 16 | insert_final_newline = ignore 17 | 18 | [MakeFile] 19 | indent_style = space 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "plugin:adonis/typescriptPackage", 4 | "prettier" 5 | ], 6 | "plugins": [ 7 | "prettier" 8 | ], 9 | "rules": { 10 | "prettier/prettier": [ 11 | "error", 12 | { 13 | "endOfLine": "auto" 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/COMMIT_CONVENTION.md: -------------------------------------------------------------------------------- 1 | ## Git Commit Message Convention 2 | 3 | > This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular). 4 | 5 | Using conventional commit messages, we can automate the process of generating the CHANGELOG file. All commits messages will automatically be validated against the following regex. 6 | 7 | ``` js 8 | /^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|ci|chore|types|build|improvement)((.+))?: .{1,50}/ 9 | ``` 10 | 11 | ## Commit Message Format 12 | A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**: 13 | 14 | > The **scope** is optional 15 | 16 | ``` 17 | feat(router): add support for prefix 18 | 19 | Prefix makes it easier to append a path to a group of routes 20 | ``` 21 | 22 | 1. `feat` is type. 23 | 2. `router` is scope and is optional 24 | 3. `add support for prefix` is the subject 25 | 4. The **body** is followed by a blank line. 26 | 5. The optional **footer** can be added after the body, followed by a blank line. 27 | 28 | ## Types 29 | Only one type can be used at a time and only following types are allowed. 30 | 31 | - feat 32 | - fix 33 | - docs 34 | - style 35 | - refactor 36 | - perf 37 | - test 38 | - workflow 39 | - ci 40 | - chore 41 | - types 42 | - build 43 | 44 | If a type is `feat`, `fix` or `perf`, then the commit will appear in the CHANGELOG.md file. However if there is any BREAKING CHANGE, the commit will always appear in the changelog. 45 | 46 | ### Revert 47 | If the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit. In the body it should say: `This reverts commit `., where the hash is the SHA of the commit being reverted. 48 | 49 | ## Scope 50 | The scope could be anything specifying place of the commit change. For example: `router`, `view`, `querybuilder`, `database`, `model` and so on. 51 | 52 | ## Subject 53 | The subject contains succinct description of the change: 54 | 55 | - use the imperative, present tense: "change" not "changed" nor "changes". 56 | - don't capitalize first letter 57 | - no dot (.) at the end 58 | 59 | ## Body 60 | 61 | Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". 62 | The body should include the motivation for the change and contrast this with previous behavior. 63 | 64 | ## Footer 65 | 66 | The footer should contain any information about **Breaking Changes** and is also the place to 67 | reference GitHub issues that this commit **Closes**. 68 | 69 | **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this. 70 | 71 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Prerequisites 4 | 5 | We do our best to reply to all the issues on time. If you will follow the given guidelines, the turn around time will be faster. 6 | 7 | - Ensure the issue isn't already reported. 8 | - Ensure you are reporting the bug in the correct repo. 9 | 10 | *Delete the above section and the instructions in the sections below before submitting* 11 | 12 | ## Description 13 | 14 | If this is a feature request, explain why it should be added. Specific use-cases are best. 15 | 16 | For bug reports, please provide as much *relevant* info as possible. 17 | 18 | ## Package version 19 | 20 | 21 | ## Error Message & Stack Trace 22 | 23 | ## Relevant Information 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Proposed changes 4 | 5 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 6 | 7 | ## Types of changes 8 | 9 | What types of changes does your code introduce? 10 | 11 | _Put an `x` in the boxes that apply_ 12 | 13 | - [ ] Bugfix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 16 | 17 | ## Checklist 18 | 19 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ 20 | 21 | - [ ] I have read the [CONTRIBUTING](https://github.com/wahyubucil/adonis-mix-asset/blob/master/CONTRIBUTING.md) doc 22 | - [ ] Lint and unit tests pass locally with my changes 23 | - [ ] I have added tests that prove my fix is effective or that my feature works. 24 | - [ ] I have added necessary documentation (if appropriate) 25 | 26 | ## Further comments 27 | 28 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .DS_STORE 4 | .nyc_output 5 | .idea 6 | .vscode/ 7 | *.sublime-project 8 | *.sublime-workspace 9 | *.log 10 | build 11 | dist 12 | shrinkwrap.yaml 13 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | HUSKY_GIT_PARAMS=$1 node ./node_modules/@adonisjs/mrm-preset/validate-commit/conventional/validate.js 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | npx doctoc README.md --title='## Table of contents' 4 | git add README.md 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | message="chore(release): %s" 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build 2 | docs 3 | *.md 4 | config.json 5 | .eslintrc.json 6 | package.json 7 | *.html 8 | *.txt 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": false, 4 | "singleQuote": true, 5 | "useTabs": false, 6 | "quoteProps": "consistent", 7 | "bracketSpacing": true, 8 | "arrowParens": "always", 9 | "printWidth": 100 10 | } 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We love pull requests. And following this guidelines will make your pull request easier to merge 4 | 5 | - [Prerequisites](#prerequisites) 6 | - [Coding style](#coding-style) 7 | - [Fix bugs by creating PR's](#fix-bugs-by-creating-prs) 8 | - [Be a part of the community](#be-a-part-of-community) 9 | - [Other notes](#other-notes) 10 | 11 | ## Prerequisites 12 | 13 | - Install [EditorConfig](http://editorconfig.org/) plugin for your code editor to make sure it uses correct settings. 14 | - Fork the repository and clone your fork. 15 | - Install dependencies: `npm install`. 16 | 17 | ## Coding style 18 | 19 | AdonisJS packages are written in Typescript. Having a brief knowledge of Typescript is required to contribute. We make use of [standard](https://standardjs.com/) to lint our code. Standard does not need a config file and comes with set of non-configurable rules. 20 | 21 | ## Fix bugs by creating PR's 22 | 23 | We appreciate every time you report a bug in the framework or related libraries. However, taking time to submit a PR can help us in fixing bugs quickly and ensure a healthy and stable eco-system. 24 | 25 | Go through the following points, before creating a new PR. 26 | 27 | 1. Create an issue discussing the bug or short-coming in the framework. 28 | 2. Once approved, go ahead and fork the REPO. 29 | 3. Make sure to start from the `develop`, since this is the up to date branch. 30 | 4. Make sure to keep commits small and relevant. 31 | 5. We follow [conventional-commits](https://github.com/conventional-changelog/conventional-changelog) to structure our commit messages. Instead of running `git commit`, you must run `npm run commit`, which will show you prompts to create a valid commit message. 32 | 6. Once done with all the changes, create a PR against the `develop` branch. 33 | 34 | ## Be a part of community 35 | 36 | We welcome you to participate in the [forum](https://github.com/adonisjs/core/discussions) and the AdonisJS [discord server](https://discord.com/invite/vDcEjq6). You are free to ask your questions and share your work or contributions made to AdonisJS eco-system. 37 | 38 | ## Other notes 39 | 40 | - Do not change version number inside the `package.json` file. 41 | - Do not update `.eslintrc.json` file. If something prevents you writing code, please create an issue for same. 42 | - If you found an error while committing with `npm run commit` like this `.husky/pre-commit: line 2: .husky/_/husky.sh: No such file or directory`. You need to run : `npx husky install` 43 | 44 | ## Need help? 45 | 46 | Feel free to ask. 47 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | 3 | Copyright 2020 Wahyu Bucil, contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adonis Mix Asset 2 | > Laravel Mix for Asset Bundler on AdonisJS 3 | 4 | [![npm-image]][npm-url] [![license-image]][license-url] [![typescript-image]][typescript-url] 5 | 6 | Adonis Mix Asset is an assets bundler based on [Laravel Mix](https://laravel-mix.com) for AdonisJS application. 7 | 8 | [Laravel Mix](https://laravel-mix.com) is an awesome assets bundler and easy to use! 9 | 10 | 11 | 12 | ## Table of contents 13 | 14 | - [Getting Started](#getting-started) 15 | - [Installation](#installation) 16 | - [Setup](#setup) 17 | - [Usage](#usage) 18 | - [Example Configuration](#example-configuration) 19 | - [View Helper](#view-helper) 20 | - [Compile Assets](#compile-assets) 21 | - [Additional Information](#additional-information) 22 | - [Gitignore](#gitignore) 23 | - [Analyze Assets Size](#analyze-assets-size) 24 | - [Enable Hot Module Replacement (HMR) / Hot Reloading](#enable-hot-module-replacement-hmr--hot-reloading) 25 | - [Use Another Mix Configuration](#use-another-mix-configuration) 26 | - [Tips on Using Typescript Asset](#tips-on-using-typescript-asset) 27 | 28 | 29 | 30 | ## Getting Started 31 | 32 | ### Installation 33 | ```bash 34 | npm i adonis-mix-asset && npm i --save-dev laravel-mix 35 | 36 | # or if using Yarn 37 | yarn add adonis-mix-asset && yarn add --dev laravel-mix 38 | ``` 39 | 40 | ### Setup 41 | ```bash 42 | node ace configure adonis-mix-asset 43 | ``` 44 | It will install the provider, command, and copy `webpack.mix.js` configuration file to the project's root folder. 45 | 46 | ## Usage 47 | 48 | ### Example Configuration 49 | The configuration file is on `webpack.mix.js`. 50 | ```js 51 | const mix = require('laravel-mix') 52 | 53 | /** 54 | * By default, AdonisJS public path for static assets is on the `./public` directory. 55 | * 56 | * If you want to change Laravel Mix public path, change the AdonisJS public path config first! 57 | * See: https://docs.adonisjs.com/guides/static-assets#the-default-directory 58 | */ 59 | mix.setPublicPath('public') 60 | 61 | // Add your assets here 62 | mix 63 | .js('resources/assets/scripts/app.js', 'scripts') 64 | .sass('resources/assets/styles/app.scss', 'styles') 65 | ``` 66 | 67 | For more information on Laravel Mix features. See [Laravel Mix Documentation](https://laravel-mix.com/docs). 68 | 69 | ### View Helper 70 | Use `mix` view helper to generate assets url. Example : 71 | ```handlebars 72 | ... 73 | 74 | 75 | 76 | 77 | ... 78 | ``` 79 | The view helper parses `mix-manifest.json` to generate assets url. 80 | 81 | ### Compile Assets 82 | Make sure before you run the command, you already configuring the `webpack.mix.js` file, and run `node ace serve` or `node ace build`. 83 | 84 | Build assets : 85 | ```bash 86 | node ace mix:build 87 | ``` 88 | Build assets and watch for file changes : 89 | ```bash 90 | node ace mix:watch 91 | ``` 92 | Build assets for production : 93 | ```bash 94 | node ace mix:build --production 95 | ``` 96 | 97 | ## Additional Information 98 | 99 | ### Gitignore 100 | Add this to your `.gitignore` file : 101 | ```.gitignore 102 | mix-manifest.json 103 | ``` 104 | Also, for example if you want to output your scripts on `public/scripts` and styles on `public/styles`, you need to add all of those folders to your `.gitignore` file. Example : 105 | ```.gitignore 106 | public/scripts 107 | public/styles 108 | ``` 109 | 110 | ### Analyze Assets Size 111 | If you want to analyze all of your asset sizes for production. Run this command : 112 | ```bash 113 | node ace mix:build --analyze --production 114 | ``` 115 | It will open your browser automatically and show an interactive treemap visualization of the contents of all your assets. 116 | 117 | If the browser doesn't open automatically. You can open it on [127.0.0.1:8888](http://127.0.0.1:8888). 118 | 119 | Analyzer preview : 120 | ![webpack bundle analyzer zoomable treemap](https://cloud.githubusercontent.com/assets/302213/20628702/93f72404-b338-11e6-92d4-9a365550a701.gif) 121 | Source : [webpack-bundle-analyzer documentation](https://github.com/webpack-contrib/webpack-bundle-analyzer#readme). 122 | 123 | ### Enable Hot Module Replacement (HMR) / Hot Reloading 124 | First, read [Laravel Mix instructions](https://laravel-mix.com/docs/hot-module-replacement) about HMR. 125 | 126 | Run this command to enable HMR : 127 | ```bash 128 | node ace mix:watch --hot 129 | ``` 130 | 131 | ### Use Another Mix Configuration 132 | If you want to use another Mix configuration, you can use `--mix-config` option either on `mix:build` or `mix:watch`. Example : 133 | ```bash 134 | node ace mix:build --mix-config prod/webpack.mix.js 135 | node ace mix:watch --mix-config prod/webpack.mix.js 136 | ``` 137 | 138 | ### Tips on Using Typescript Asset 139 | If you're planning to use Typescript asset for your Front-End, here are some tips to get started. 140 | 141 | For example if you want to put your scripts on `resources/assets/scripts`, then you need to create `tsconfig.json` in those folder. That way, it will prevent conflict between your Front-End script and Back-End script. 142 | 143 | Here's an example `tsconfig.json` you can use : 144 | ```json 145 | { 146 | "compilerOptions": { 147 | "target": "es5", 148 | "lib": ["dom", "dom.iterable", "esnext"], 149 | "allowJs": true, 150 | "skipLibCheck": true, 151 | "esModuleInterop": true, 152 | "allowSyntheticDefaultImports": true, 153 | "strict": true, 154 | "forceConsistentCasingInFileNames": true, 155 | "module": "esnext", 156 | "moduleResolution": "node", 157 | "resolveJsonModule": true, 158 | "noUnusedLocals": true, 159 | "incremental": true, 160 | "noUnusedParameters": true, 161 | "declaration": false, 162 | "strictNullChecks": true 163 | }, 164 | "include": ["./"] 165 | } 166 | ``` 167 | 168 | [typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript 169 | [typescript-url]: "typescript" 170 | 171 | [npm-image]: https://img.shields.io/npm/v/adonis-mix-asset.svg?style=for-the-badge&logo=npm 172 | [npm-url]: https://npmjs.org/package/adonis-mix-asset "npm" 173 | 174 | [license-image]: https://img.shields.io/npm/l/adonis-mix-asset?color=blueviolet&style=for-the-badge 175 | [license-url]: LICENSE.md "license" 176 | -------------------------------------------------------------------------------- /commands/Mix/Base.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { BaseCommand } from '@adonisjs/ace' 11 | import { flags } from '@adonisjs/core/build/standalone' 12 | import { spawn } from 'child_process' 13 | 14 | /** 15 | * Base class to provide helpers for Mix commands 16 | */ 17 | export abstract class BaseMix extends BaseCommand { 18 | @flags.string({ 19 | description: "The path to your Mix configuration file. Default: 'webpack.mix.js'", 20 | }) 21 | public mixConfig = 'webpack.mix.js' 22 | 23 | @flags.boolean({ description: 'Enable progress reporting. Default: true' }) 24 | public progress = true 25 | 26 | protected get isTesting() { 27 | return process.env.TESTING 28 | } 29 | 30 | protected get isTTY() { 31 | if (this.isTesting && process.env.IS_TTY !== undefined) { 32 | return process.env.IS_TTY === 'true' 33 | } 34 | 35 | if (this.isTesting && process.stdout.isTTY === undefined) { 36 | return true 37 | } 38 | 39 | return process.stdout.isTTY 40 | } 41 | 42 | protected runScript(script: string, scriptEnv: NodeJS.ProcessEnv) { 43 | if (this.isTesting) { 44 | process.stdout.write(JSON.stringify({ script, env: scriptEnv })) 45 | return 46 | } 47 | 48 | const child = spawn(script, { 49 | stdio: 'inherit', 50 | shell: true, 51 | env: { ...process.env, ...scriptEnv }, 52 | }) 53 | 54 | child.on('exit', (code, signal) => { 55 | if (code === null) { 56 | code = signal === 'SIGINT' ? 130 : 1 57 | } 58 | 59 | process.exitCode = code 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /commands/Mix/Build.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { flags } from '@adonisjs/core/build/standalone' 11 | import { existsSync } from 'fs' 12 | import { relative } from 'path' 13 | import { BaseMix } from './Base' 14 | 15 | /** 16 | * Command to build assets 17 | * 18 | * Reference: https://github.com/JeffreyWay/laravel-mix/blob/8cfacdde47/bin/cli.js 19 | */ 20 | export default class MixBuild extends BaseMix { 21 | public static commandName = 'mix:build' 22 | public static description = 'Compile Mix' 23 | public static settings = { 24 | stayAlive: true, 25 | } 26 | 27 | @flags.boolean({ description: 'Build assets for production' }) 28 | public production: boolean 29 | 30 | @flags.boolean({ description: 'Open bundle analyzer' }) 31 | public analyze: boolean 32 | 33 | public async run() { 34 | const mixConfigPath = this.application.makePath(this.mixConfig) 35 | if (!existsSync(mixConfigPath)) { 36 | this.logger.error(`The Mix configuration file '${this.mixConfig}' is not found`) 37 | return 38 | } 39 | 40 | let commandScript: string 41 | if (this.isTTY && this.progress) commandScript = 'npx webpack --progress' 42 | else commandScript = 'npx webpack' 43 | 44 | let configPath = 'laravel-mix/setup/webpack.config.js' 45 | if (this.analyze) configPath = '../../setup/webpack.config.js' 46 | 47 | const webpackConfigPath = relative(this.application.appRoot, require.resolve(configPath)) 48 | 49 | const script = [commandScript, `--config="${webpackConfigPath}"`].join(' ') 50 | 51 | const scriptEnv = { 52 | NODE_ENV: this.production ? 'production' : 'development', 53 | MIX_FILE: this.mixConfig, 54 | } 55 | 56 | this.runScript(script, scriptEnv) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /commands/Mix/Watch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { flags } from '@adonisjs/core/build/standalone' 11 | import { existsSync } from 'fs' 12 | import { relative } from 'path' 13 | import { BaseMix } from './Base' 14 | 15 | /** 16 | * Command to watch assets 17 | * 18 | * Reference: https://github.com/JeffreyWay/laravel-mix/blob/8cfacdde47/bin/cli.js 19 | */ 20 | export default class MixWatch extends BaseMix { 21 | public static commandName = 'mix:watch' 22 | public static description = 'Build and watch files for changes' 23 | public static settings = { 24 | stayAlive: true, 25 | } 26 | 27 | @flags.boolean({ description: 'Enable hot reloading' }) 28 | public hot: boolean 29 | 30 | @flags.boolean({ description: 'Enable https' }) 31 | public https: boolean 32 | 33 | public async run() { 34 | const mixConfigPath = this.application.makePath(this.mixConfig) 35 | if (!existsSync(mixConfigPath)) { 36 | this.logger.error(`The Mix configuration file '${this.mixConfig}' is not found`) 37 | return 38 | } 39 | 40 | let commandScript: string 41 | if (!this.hot) { 42 | if (this.isTTY && this.progress) commandScript = 'npx webpack --progress --watch' 43 | else commandScript = 'npx webpack --watch' 44 | } else { 45 | commandScript = 'npx webpack serve --hot' + (this.https ? ' --https' : '') 46 | } 47 | 48 | const webpackConfigPath = relative( 49 | this.application.appRoot, 50 | require.resolve('laravel-mix/setup/webpack.config.js') 51 | ) 52 | 53 | const script = [commandScript, `--config="${webpackConfigPath}"`].join(' ') 54 | 55 | const scriptEnv = { 56 | NODE_ENV: 'development', 57 | MIX_FILE: this.mixConfig, 58 | } 59 | 60 | this.runScript(script, scriptEnv) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /commands/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | export default [ 11 | 'adonis-mix-asset/build/commands/Mix/Build', 12 | 'adonis-mix-asset/build/commands/Mix/Watch', 13 | ] 14 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": false, 3 | "license": "MIT", 4 | "services": [], 5 | "minNodeVersion": "14.17.0", 6 | "probotApps": [] 7 | } 8 | -------------------------------------------------------------------------------- /instructions.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import * as sinkStatic from '@adonisjs/sink' 11 | import { ApplicationContract } from '@ioc:Adonis/Core/Application' 12 | import { join } from 'path' 13 | 14 | const MIX_CONFIG_TEMPLATE_STUB = join(__dirname, './templates', 'webpack.mix.txt') 15 | 16 | export default async function instructions( 17 | projectRoot: string, 18 | _: ApplicationContract, 19 | { logger, files }: typeof sinkStatic 20 | ) { 21 | const mixConfig = new files.MustacheFile(projectRoot, 'webpack.mix.js', MIX_CONFIG_TEMPLATE_STUB) 22 | if (mixConfig.exists()) { 23 | logger.action('create').skipped('webpack.mix.js', 'File already exists') 24 | } else { 25 | mixConfig.apply({}).commit() 26 | logger.action('create').succeeded('webpack.mix.js') 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /japaFile.js: -------------------------------------------------------------------------------- 1 | require('@adonisjs/require-ts/build/register') 2 | 3 | const { configure } = require('japa') 4 | 5 | configure({ 6 | files: ['test/**/*.spec.ts'], 7 | }) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "adonis-mix-asset", 3 | "version": "3.0.0", 4 | "description": "Laravel Mix for Asset Bundler on AdonisJS", 5 | "main": "build/providers/MixAssetProvider.js", 6 | "files": [ 7 | "build/commands", 8 | "build/providers", 9 | "build/setup", 10 | "build/src", 11 | "build/templates", 12 | "build/instructions.js" 13 | ], 14 | "scripts": { 15 | "mrm": "mrm --preset=@adonisjs/mrm-preset", 16 | "pretest": "npm run lint", 17 | "test": "node japaFile.js", 18 | "clean": "del build", 19 | "compile": "npm run lint && npm run clean && tsc && npm run copy:files", 20 | "copy:files": "copyfiles \"templates/*\" build", 21 | "build": "npm run compile", 22 | "prepublishOnly": "npm run build", 23 | "lint": "eslint . --ext=.ts", 24 | "format": "prettier --write .", 25 | "commit": "git-cz", 26 | "release": "np", 27 | "version": "npm run build", 28 | "sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json wahyubucil/adonis-mix-asset" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/wahyubucil/adonis-mix-asset.git" 33 | }, 34 | "keywords": [ 35 | "AdonisJS", 36 | "Adonis Laravel Mix", 37 | "Adonis asset bundler" 38 | ], 39 | "author": "wahyubucil", 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/wahyubucil/adonis-mix-asset/issues" 43 | }, 44 | "homepage": "https://github.com/wahyubucil/adonis-mix-asset#readme", 45 | "devDependencies": { 46 | "@adonisjs/core": "^5.1.7", 47 | "@adonisjs/mrm-preset": "^4.0.1", 48 | "@adonisjs/require-ts": "^2.0.4", 49 | "@adonisjs/sink": "^5.1.3", 50 | "@adonisjs/view": "^6.0.2", 51 | "@types/node": "^15.3.0", 52 | "@types/webpack-bundle-analyzer": "^4.4.0", 53 | "commitizen": "^4.2.4", 54 | "copyfiles": "^2.4.1", 55 | "cz-conventional-changelog": "^3.3.0", 56 | "del-cli": "^3.0.1", 57 | "doctoc": "^2.0.0", 58 | "eslint": "^7.26.0", 59 | "eslint-config-prettier": "^8.3.0", 60 | "eslint-plugin-adonis": "^1.3.1", 61 | "eslint-plugin-prettier": "^3.4.0", 62 | "github-label-sync": "^2.0.0", 63 | "husky": "^6.0.0", 64 | "japa": "^3.1.1", 65 | "laravel-mix": "^6.0.19", 66 | "mrm": "^3.0.1", 67 | "np": "^7.5.0", 68 | "prettier": "^2.3.0", 69 | "typescript": "^4.2.4", 70 | "webpack": "^5.37.0" 71 | }, 72 | "dependencies": { 73 | "webpack-bundle-analyzer": "^4.4.2" 74 | }, 75 | "peerDependencies": { 76 | "@adonisjs/core": "^5.1.7", 77 | "@adonisjs/view": "^6.0.2", 78 | "laravel-mix": "^6.0.19" 79 | }, 80 | "config": { 81 | "commitizen": { 82 | "path": "cz-conventional-changelog" 83 | } 84 | }, 85 | "np": { 86 | "contents": ".", 87 | "anyBranch": false 88 | }, 89 | "adonisjs": { 90 | "instructions": "./build/instructions.js", 91 | "commands": [ 92 | "adonis-mix-asset/build/commands" 93 | ], 94 | "providers": [ 95 | "adonis-mix-asset" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /providers/MixAssetProvider.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { ApplicationContract } from '@ioc:Adonis/Core/Application' 11 | import { existsSync, readFileSync } from 'fs' 12 | import { mixAsset } from '../src/mixAsset' 13 | 14 | export default class MixAssetProvider { 15 | constructor(protected app: ApplicationContract) {} 16 | 17 | /** 18 | * Returns the manifest file contents. During development, we make use of the 19 | * `readFileSync` method to read the fresh contents on every call 20 | */ 21 | private getManifestContents(manifestPath: string) { 22 | if (this.app.inProduction) { 23 | return require(manifestPath) 24 | } 25 | 26 | return JSON.parse(readFileSync(manifestPath, 'utf-8')) 27 | } 28 | 29 | public boot() { 30 | const View = this.app.container.resolveBinding('Adonis/Core/View') 31 | const manifestPath = this.app.publicPath('mix-manifest.json') 32 | if (existsSync(manifestPath)) { 33 | View.global('mix', (path: string) => 34 | mixAsset(this.app, this.getManifestContents(manifestPath), path) 35 | ) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /setup/webpack.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import type { Configuration } from 'webpack' 11 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' 12 | 13 | const webpackConfig = require('laravel-mix/setup/webpack.config.js') as () => Promise 14 | 15 | export default async () => { 16 | const config = await webpackConfig() 17 | config.plugins?.push(new BundleAnalyzerPlugin()) 18 | 19 | return config 20 | } 21 | -------------------------------------------------------------------------------- /src/mixAsset.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * adonis-mix-asset 3 | * 4 | * (c) Wahyu Budi Saputra 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | import { ApplicationContract } from '@ioc:Adonis/Core/Application' 11 | import { existsSync, readFileSync } from 'fs' 12 | 13 | // Reference: https://github.com/laravel/framework/blob/990e0e7/src/Illuminate/Foundation/Mix.php 14 | export function mixAsset( 15 | application: ApplicationContract, 16 | manifest: Record, 17 | path: string 18 | ) { 19 | if (!path) return 20 | 21 | if (!path.startsWith('/')) path = '/' + path 22 | 23 | if (!application.inProduction && existsSync(application.publicPath('hot'))) { 24 | const url = readFileSync(application.publicPath('hot'), 'utf-8').trim() 25 | 26 | if (url.startsWith('http://') || url.startsWith('https://')) { 27 | return url.substring(url.indexOf(':') + 1) + path 28 | } 29 | 30 | return '//localhost:8080' + path 31 | } 32 | 33 | if (!manifest[path]) throw new Error(`Unable to locate Mix file: ${path}.`) 34 | return manifest[path] 35 | } 36 | -------------------------------------------------------------------------------- /templates/webpack.mix.txt: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix') 2 | 3 | /** 4 | * By default, AdonisJS public path for static assets is on the `./public` directory. 5 | * 6 | * If you want to change Laravel Mix public path, change the AdonisJS public path config first! 7 | * See: https://docs.adonisjs.com/guides/static-assets#the-default-directory 8 | */ 9 | mix.setPublicPath('public') 10 | 11 | // Add your assets here 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@adonisjs/mrm-preset/_tsconfig", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "skipLibCheck": true, 6 | "types": ["@adonisjs/core", "@adonisjs/view"] 7 | } 8 | } 9 | --------------------------------------------------------------------------------