├── .eslintignore ├── .gitignore ├── default-serve.js ├── .eslintrc ├── defaults.js ├── serve-config-hook.js ├── LICENSE ├── package.json ├── prompts.js ├── CHANGELOG.md ├── README.md ├── generator.js └── index.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | template 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea 4 | -------------------------------------------------------------------------------- /default-serve.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: '0.0.0.0', 3 | port: 8080, 4 | https: false 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:vue-libs/recommended"], 3 | "env": { 4 | }, 5 | "globals": { 6 | "device": true 7 | }, 8 | "rules": { 9 | "indent": ["error", 2, { "MemberExpression": "off" }] 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /defaults.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | cordovaPath: 'src-cordova', 3 | id: 'com.vue.example.app', 4 | appName: 'VueExampleAppName', 5 | platforms: ['android', 'ios', 'browser', 'osx', 'electron'], 6 | routerMode: 'hash', 7 | gitIgnoreContent: '*\n*/\n!.gitignore' 8 | } 9 | -------------------------------------------------------------------------------- /serve-config-hook.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { info } = require('@vue/cli-shared-utils') 3 | 4 | const url = process.env.CORDOVA_WEBVIEW_SRC 5 | const cordovaConfigPath = process.env.CORDOVA_PREPARE_CONFIG 6 | if (!url || !cordovaConfigPath) { 7 | return 8 | } 9 | info(`updating ${cordovaConfigPath} content to ${url}`) 10 | 11 | let cordovaConfig = fs.readFileSync(cordovaConfigPath, 'utf-8') 12 | const lines = cordovaConfig.split(/\r?\n/g).reverse() 13 | const regexContent = /\s+ line.match(regexContent)) 15 | const allowNavigation = ` ` 16 | if (contentIndex >= 0) { 17 | lines[contentIndex] = ` ` 18 | if (url) { 19 | lines.splice(contentIndex, 0, allowNavigation) 20 | } 21 | cordovaConfig = lines.reverse().join('\n') 22 | fs.writeFileSync(cordovaConfigPath, cordovaConfig) 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 m0dch3n 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli-plugin-cordova", 3 | "version": "2.4.1", 4 | "description": "vue-cli 3.x plugin for Apache Cordova", 5 | "main": "index.js", 6 | "scripts": { 7 | "release": "standard-version", 8 | "lint": "eslint *.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/m0dch3n/vue-cli-plugin-cordova.git" 13 | }, 14 | "keywords": [ 15 | "vue", 16 | "cordova", 17 | "vue-cli" 18 | ], 19 | "author": "m0dch3n", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/m0dch3n/vue-cli-plugin-cordova/issues" 23 | }, 24 | "homepage": "https://github.com/m0dch3n/vue-cli-plugin-cordova#readme", 25 | "dependencies": { 26 | "@vue/cli-shared-utils": "^4.2.3", 27 | "address": "^1.1.2", 28 | "cross-env": "^5.2.0", 29 | "cross-spawn": "^6.0.5", 30 | "hasbin": "^1.2.3", 31 | "html-webpack-include-assets-plugin": "^1.0.4", 32 | "portfinder": "^1.0.25" 33 | }, 34 | "devDependencies": { 35 | "minimist": "^1.2.5", 36 | "acorn": "^6.4.1", 37 | "eslint": "^5.16.0", 38 | "eslint-plugin-vue-libs": "^4.0.0", 39 | "standard-version": "^8.0.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /prompts.js: -------------------------------------------------------------------------------- 1 | const hasbin = require('hasbin') 2 | const defaults = require('./defaults') 3 | const hasCordova = hasbin.sync('cordova') 4 | 5 | const prompts = [ 6 | { 7 | name: 'cordovaPath', 8 | type: 'string', 9 | message: 'Name of folder where cordova should be installed', 10 | default: defaults.cordovaPath, 11 | validate: opt => opt && opt.length >= 0 12 | }, 13 | { 14 | name: 'id', 15 | type: 'string', 16 | message: 'ID of the app', 17 | default: defaults.id, 18 | validate: opt => opt && opt.length >= 0 19 | }, 20 | { 21 | name: 'appName', 22 | type: 'string', 23 | message: 'Name of the app', 24 | default: defaults.appName, 25 | validate: opt => opt && opt.length >= 0 26 | }, 27 | { 28 | name: 'platforms', 29 | type: 'checkbox', 30 | message: 'Select Platforms:', 31 | choices: [ 32 | { 33 | name: 'Android', 34 | value: 'android', 35 | checked: !!defaults.platforms['android'] 36 | }, 37 | { 38 | name: 'iOS', 39 | value: 'ios', 40 | checked: !!defaults.platforms['ios'] 41 | }, 42 | { 43 | name: 'Browser', 44 | value: 'browser', 45 | checked: !!defaults.platforms['browser'] 46 | }, 47 | { 48 | name: 'OSX', 49 | value: 'osx', 50 | checked: !!defaults.platforms['osx'] 51 | }, 52 | { 53 | name: 'Electron', 54 | value: 'electron', 55 | checked: !!defaults.platforms['electron'] 56 | } 57 | ] 58 | } 59 | ] 60 | 61 | module.exports = hasCordova ? prompts : null 62 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [2.4.1](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.4.0...v2.4.1) (2020-04-01) 6 | 7 | ## [2.4.0](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.8...v2.4.0) (2020-01-10) 8 | 9 | 10 | ### Features 11 | 12 | * specifying a device target ([#102](https://github.com/m0dch3n/vue-cli-plugin-cordova/issues/102)) ([baa9cc0](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/baa9cc0)) 13 | 14 | 15 | 16 | ### [2.3.8](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.7...v2.3.8) (2019-12-20) 17 | 18 | 19 | 20 | ### [2.3.7](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.6...v2.3.7) (2019-11-19) 21 | 22 | 23 | ### Bug Fixes 24 | 25 | * output missing url or cordovaConfigPath ([e62ad1e](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/e62ad1e)) 26 | 27 | 28 | 29 | ### [2.3.6](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.5...v2.3.6) (2019-06-25) 30 | 31 | 32 | 33 | ### [2.3.5](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.4...v2.3.5) (2019-06-24) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * better readme ([715ada9](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/715ada9)) 39 | 40 | 41 | 42 | ### [2.3.4](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.3...v2.3.4) (2019-06-24) 43 | 44 | 45 | 46 | ### [2.3.3](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.2...v2.3.3) (2019-06-24) 47 | 48 | 49 | 50 | ### [2.3.2](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.1...v2.3.2) (2019-06-24) 51 | 52 | 53 | 54 | ### [2.3.1](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.3.0...v2.3.1) (2019-06-20) 55 | 56 | 57 | ### Bug Fixes 58 | 59 | * wrong command name in defaultModes ([d0502d9](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/d0502d9)) 60 | 61 | 62 | 63 | ## [2.3.0](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.2.2...v2.3.0) (2019-06-20) 64 | 65 | 66 | ### Features 67 | 68 | * build-only-www fix [#65](https://github.com/m0dch3n/vue-cli-plugin-cordova/issues/65) ([7cfb99d](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/7cfb99d)) 69 | 70 | 71 | 72 | ### [2.2.2](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.2.1...v2.2.2) (2019-06-20) 73 | 74 | 75 | 76 | ### [2.2.1](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.2.0...v2.2.1) (2019-06-20) 77 | 78 | 79 | 80 | ## [2.2.0](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.1.4...v2.2.0) (2019-06-20) 81 | 82 | 83 | ### Features 84 | 85 | * Instead of updating the config.xml, a cordova hook is now used. If you are upgrading, please add to your config.xml ([c7a969a](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/c7a969a)) 86 | 87 | 88 | 89 | ### [2.1.4](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.1.3...v2.1.4) (2019-06-20) 90 | 91 | 92 | ### Bug Fixes 93 | 94 | * updated security vulnerabilities ([60f8bbf](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/60f8bbf)) 95 | 96 | 97 | 98 | 99 | ## [2.1.3](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.1.2...v2.1.3) (2019-03-22) 100 | 101 | 102 | 103 | 104 | ## [2.1.2](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.1.1...v2.1.2) (2019-02-12) 105 | 106 | 107 | ### Bug Fixes 108 | 109 | * lodash 4.17.10 security vulnerability ([bb12338](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/bb12338)) 110 | 111 | 112 | 113 | 114 | ## [2.1.1](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.1.0...v2.1.1) (2019-02-01) 115 | 116 | 117 | 118 | 119 | # [2.1.0](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.0.9...v2.1.0) (2019-01-31) 120 | 121 | 122 | ### Features 123 | 124 | * Add support for macOS ([858fc19](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/858fc19)) 125 | 126 | 127 | 128 | 129 | ## [2.0.9](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.0.8...v2.0.9) (2019-01-02) 130 | 131 | 132 | 133 | 134 | ## [2.0.8](https://github.com/m0dch3n/vue-cli-plugin-cordova/compare/v2.0.7...v2.0.8) (2018-10-09) 135 | 136 | 137 | ### Bug Fixes 138 | 139 | * process.env.CORDOVA_PLATFORM undefined in serve-browser and devServer not working ([cfb5db8](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/cfb5db8)) 140 | 141 | 142 | 143 | 144 | ## 2.0.7 (2018-10-09) 145 | 146 | 147 | ### Bug Fixes 148 | 149 | * process.env.NODE_ENV === 'production' returns false in a production build [#17](https://github.com/m0dch3n/vue-cli-plugin-cordova/issues/17) ([522fe02](https://github.com/m0dch3n/vue-cli-plugin-cordova/commit/522fe02)) 150 | 151 | 152 | 153 | 154 | ## 2.0.6 (2018-10-02) 155 | 156 | 157 | 158 | 159 | ## 2.0.5 (2018-10-02) 160 | 161 | 162 | 163 | 164 | ## 2.0.4 (2018-09-29) 165 | 166 | 167 | 168 | 169 | ## 2.0.3 (2018-09-20) 170 | 171 | 172 | 173 | 174 | ## 2.0.2 (2018-09-17) 175 | 176 | 177 | 178 | 179 | ## 2.0.1 (2018-09-16) 180 | 181 | 182 | 183 | 184 | ## 0.0.3 (2018-09-14) 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cli-plugin-cordova 2 | [Vue CLI 3.x](https://github.com/vuejs/vue-cli) plugin for Apache Cordova. 3 | 4 | Integrate Cordova into Vue Cli App 5 | 6 | ## How To 7 | Create Vue App 8 | ```sh 9 | $ npm install -g @vue/cli 10 | $ vue create my-app 11 | $ cd my-app 12 | $ npm install -g cordova # If cordova is not already installed 13 | ``` 14 | 15 | **Add the plugin to your vue app.** 16 | ```sh 17 | $ vue add cordova 18 | ``` 19 | 20 | ## Usage 21 | Prepare 22 | ```sh 23 | $ npm run cordova-prepare # prepare for build (you can run this command, when you checkouted your project from GIT, it's like npm install) 24 | ``` 25 | Android 26 | ```sh 27 | $ npm run cordova-serve-android # Development Android 28 | $ npm run cordova-build-android # Build Android 29 | $ npm run cordova-build-only-www-android # Build only files to src-cordova 30 | ``` 31 | IOS 32 | ```sh 33 | $ npm run cordova-serve-ios # Development IOS 34 | $ npm run cordova-build-ios # Build IOS 35 | $ npm run cordova-build-only-www-ios # Build only files to src-cordova 36 | ``` 37 | OSX 38 | ```sh 39 | $ npm run cordova-serve-osx # Development OSX 40 | $ npm run cordova-build-osx # Build OSX 41 | $ npm run cordova-build-only-www-osx # Build only files to src-cordova 42 | ``` 43 | Browser 44 | ```sh 45 | $ npm run cordova-serve-browser # Development Browser 46 | $ npm run cordova-build-browser # Build Browser 47 | $ npm run cordova-build-only-www-browser # Build only files to src-cordova 48 | ``` 49 | Electron 50 | ```sh 51 | $ npm run cordova-serve-electron # Development Electron 52 | $ npm run cordova-build-electron # Build Electron 53 | $ npm run cordova-build-only-www-electron # Build only files to src-cordova 54 | ``` 55 | ## IMPORTANT 56 | 57 | * Path rewriting etc does not work under Cordova, that's why it's important to use router 'hash' mode, if you run or build for Cordova. **history mode does not** work! The plugin already tries to fix this automatically... 58 | 59 | * Assets and Scripts in vue's public folder need to have a dynamic path, because depending on dev or production build, you have different bases. In dev it's normally **'/'** and in production it's **'file:///android_asset/www/'**. In other words, if you have i.e. an image under **'public/images/me.jpg'**, the relative url would be **img='images/me.jpg'** 60 | 61 | * You need some experience with Cordova, to solve many issues, like having the right Java JDK, Android SDK, XTools, Signing an App, Publishing an App etc. If you encounter issues related to Cordova etc, please don't post them this issue tracker. 62 | 63 | * If you are upgrading from an older release, please add `` to your config.xml 64 | 65 | * The devserver will run under https from now on, so make sure your rest & api endpoints are available under https, and have a correct CORS setup 66 | 67 | ## What is the plugin doing ? 68 | ### During installation 69 | 70 | During installation, the plugin is setting some important variables, modifying the router mode and executing some cordova commands. 71 | 72 | * Setting **baseUrl** in vue.config.js to '' because in cordova production, files are served from **file://android_asset/www/** 73 | * Setting cordovaPath in **vue.config.js** 74 | * Checking if **router** is available and modify router mode to **'hash'** if process.env.CORDOVA_PLATFORM is set 75 | * Adding ignore paths for cordova in **.gitignore** 76 | * Executing '**cordova create cordovaPath id appName**' (cordovaPath, id and appName will be **prompted**) 77 | * Adding cordova before_prepare hook in **config.xml** 78 | * Executing '**cordova platform add platform**' (platform will be prompted) 79 | 80 | ### In development mode 81 | 82 | In development mode (`npm run cordova-serve-*`), the plugin is starting the dev server, and creating an app with a webview, showing your dev server page. 83 | 84 | It is doing this by: 85 | 86 | * Adding **cordova.js** to your **index.html** 87 | * Defining **process.env.CORDOVA_PLATFORM** to **android**, **ios**, **osx**, **browser** or **electron** 88 | * Starting the Dev Server 89 | * Executing '**cordova clean**' 90 | * Executing '**cordova run platform**' 91 | * Pointing the cordova **config.xml** to Dev Server in hook 92 | 93 | ### In Production mode 94 | 95 | In production mode (`npm run cordova-build-*`), the plugin is building the app, with all it's assets and files etc locally in the package. The webview is showing file:///android_asset/www/index.html 96 | 97 | It is doing this by: 98 | 99 | * Adding **cordova.js** to your **index.html** 100 | * Defining **process.env.CORDOVA_PLATFORM** to **android**, **ios**, **osx**, **browser** or **electron** 101 | * Building the app, output to **/src-cordova/www** 102 | * Executing '**cordova clean**' 103 | * Executing '**cordova build platform --release**' 104 | 105 | ## Please note 106 | 107 | * For a production build, you need to **manually sign** the app, in order to be able to install it on your device, or publish it in the app store. 108 | * You need to handle cordova's **"deviceready"** etc in your app 109 | * **Cordova Plugins** can be added under /src-cordova by executing '**cordova plugin add PLUGIN**' 110 | * If you want to **debug** your build app, using **chrome devtools**, build your app with '**cordova build platform --debug**' and make sure /src-cordova/www has your **latest build** by running **cordova-build-only-www-platform** 111 | 112 | ## License 113 | 114 | MIT 115 | 116 | ## Credits 117 | 118 | Credits go to 119 | * @dekimasoon https://github.com/dekimasoon/vue-cli-plugin-cordova 120 | * @quasarframework https://github.com/quasarframework/quasar-cli 121 | 122 | Because my approach for this plugin, was inspired by theirs! 123 | -------------------------------------------------------------------------------- /generator.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const hasbin = require('hasbin') 3 | const defaults = require('./defaults') 4 | const spawn = require('cross-spawn') 5 | const { info } = require('@vue/cli-shared-utils') 6 | 7 | module.exports = (api, options) => { 8 | // early return if cordova binary is not found 9 | const hasCordova = hasbin.sync('cordova') 10 | if (!hasCordova) { 11 | api.exitLog(`Unable to find cordova binary, make sure it's installed.`, 'error') 12 | return 13 | } 14 | 15 | // cordova options 16 | const cordovaPath = options.cordovaPath || defaults.cordovaPath 17 | const id = options.id || defaults.id 18 | const appName = options.appName || defaults.appName 19 | const platforms = options.platforms || defaults.platforms 20 | 21 | api.extendPackage({ 22 | scripts: { 23 | 'cordova-serve-android': 'cross-env CORDOVA_PLATFORM=android vue-cli-service cordova-serve-android', 24 | 'cordova-build-android': 'cross-env CORDOVA_PLATFORM=android vue-cli-service cordova-build-android', 25 | 'cordova-build-only-www-android': 'cross-env CORDOVA_PLATFORM=android vue-cli-service cordova-build-only-www-android', 26 | 'cordova-serve-ios': 'cross-env CORDOVA_PLATFORM=ios vue-cli-service cordova-serve-ios', 27 | 'cordova-build-ios': 'cross-env CORDOVA_PLATFORM=ios vue-cli-service cordova-build-ios', 28 | 'cordova-build-only-www-ios': 'cross-env CORDOVA_PLATFORM=ios vue-cli-service cordova-build-only-www-ios', 29 | 'cordova-serve-browser': 'cross-env CORDOVA_PLATFORM=browser vue-cli-service cordova-serve-browser', 30 | 'cordova-build-browser': 'cross-env CORDOVA_PLATFORM=browser vue-cli-service cordova-build-browser', 31 | 'cordova-build-only-www-browser': 'cross-env CORDOVA_PLATFORM=browser vue-cli-service cordova-build-only-www-browser', 32 | 'cordova-serve-osx': 'cross-env CORDOVA_PLATFORM=osx vue-cli-service cordova-serve-osx', 33 | 'cordova-build-osx': 'cross-env CORDOVA_PLATFORM=osx vue-cli-service cordova-build-osx', 34 | 'cordova-build-only-www-osx': 'cross-env CORDOVA_PLATFORM=osx vue-cli-service cordova-build-only-www-osx', 35 | 'cordova-serve-electron': 'cross-env CORDOVA_PLATFORM=electron vue-cli-service cordova-serve-electron', 36 | 'cordova-build-electron': 'cross-env CORDOVA_PLATFORM=electron vue-cli-service cordova-build-electron', 37 | 'cordova-build-only-www-electron': 'cross-env CORDOVA_PLATFORM=electron vue-cli-service cordova-build-only-www-electron', 38 | 'cordova-prepare': 'vue-cli-service cordova-prepare' 39 | }, 40 | vue: { 41 | publicPath: '', 42 | pluginOptions: { 43 | cordovaPath 44 | } 45 | } 46 | }) 47 | 48 | api.postProcessFiles(files => { 49 | const hasTS = api.hasPlugin('typescript') 50 | 51 | // router 52 | if (api.hasPlugin('router')) { 53 | let cordovaRouterMode = `process.env.CORDOVA_PLATFORM ? 'hash' : ` 54 | const routerFilePath = `src/router.${hasTS ? 'ts' : 'js'}` 55 | const routerFile = files[routerFilePath] 56 | if (routerFile) { 57 | const lines = routerFile.split(/\r?\n/g).reverse() 58 | const regex = /\s+mode:\s('|"?\w+'|"?)/ 59 | const modeIndex = lines.findIndex(line => line.match(regex)) 60 | if (modeIndex >= 0) { 61 | const matches = lines[modeIndex].match(regex) 62 | const routerMode = matches[1] 63 | if (routerMode.includes('"')) { 64 | cordovaRouterMode = cordovaRouterMode.replace(`'hash'`, `"hash"`) 65 | } 66 | const newRouterMode = cordovaRouterMode + routerMode 67 | lines[modeIndex] = lines[modeIndex].replace(routerMode, newRouterMode) 68 | api.exitLog('Updated ' + routerFilePath + ' : ' + newRouterMode) 69 | } else { 70 | if (routerFile.includes('mode:')) { 71 | api.exitLog(`Unable to modify current router mode, make sure it's 'hash'`, 'warn') 72 | } 73 | } 74 | files[routerFilePath] = lines.reverse().join('\n') 75 | } else { 76 | api.exitLog(`Unable to find router file, make sure router mode is 'hash'`, 'warn') 77 | } 78 | } 79 | }) 80 | 81 | api.onCreateComplete(() => { 82 | // .gitignore - not included in files on postProcessFiles 83 | const ignorePath = '.gitignore' 84 | const ignoreCompletePath = api.resolve(ignorePath) 85 | const ignore = fs.existsSync(ignoreCompletePath) 86 | ? fs.readFileSync(ignoreCompletePath, 'utf-8') 87 | : '' 88 | var ignoreContent = '\n# Cordova\n' 89 | const folders = ['platforms', 'plugins'] 90 | folders.forEach(folder => { 91 | ignoreContent += `/${cordovaPath}/${folder}\n` 92 | }) 93 | ignoreContent += '/public/cordova.js\n' 94 | 95 | fs.writeFileSync(ignoreCompletePath, ignore + ignoreContent) 96 | api.exitLog(`Updated ${ignorePath} : ${ignoreContent}`) 97 | 98 | // cordova 99 | spawn.sync('cordova', [ 100 | 'create', 101 | cordovaPath, 102 | id, 103 | appName 104 | ], { 105 | env: process.env, 106 | stdio: 'inherit', // pipe to console 107 | encoding: 'utf-8' 108 | }) 109 | api.exitLog(`Executed 'cordova create ${cordovaPath} ${id} ${appName}'`) 110 | 111 | const wwwIgnorePath = api.resolve(`${cordovaPath}/www/.gitignore`) 112 | api.exitLog(`Creating file: ${wwwIgnorePath}`) 113 | fs.writeFileSync(wwwIgnorePath, defaults.gitIgnoreContent) 114 | 115 | // platforms 116 | const srcCordovaPath = api.resolve(cordovaPath) 117 | platforms.forEach(platform => { 118 | info(`Adding platform ${platform}`) 119 | spawn.sync('cordova', [ 120 | 'platform', 121 | 'add', 122 | platform 123 | ], { 124 | cwd: srcCordovaPath, 125 | env: process.env, 126 | stdio: 'inherit', // pipe to console 127 | encoding: 'utf-8' 128 | }) 129 | api.exitLog(`Executed 'cordova platform add ${platform}' in folder ${srcCordovaPath}`) 130 | }) 131 | 132 | // config.xml - add hook 133 | const configPath = `${cordovaPath}/config.xml` 134 | const configCompletePath = api.resolve(configPath) 135 | let cordovaConfig = fs.existsSync(configCompletePath) 136 | ? fs.readFileSync(configCompletePath, 'utf-8') 137 | : '' 138 | const lines = cordovaConfig.split(/\r?\n/g) 139 | const regexContent = /\s+ line.match(regexContent)) 141 | if (contentIndex >= 0) { 142 | lines.splice(contentIndex, 0, 143 | ' ', 144 | ' ' 145 | ) 146 | cordovaConfig = lines.join('\n') 147 | fs.writeFileSync(configCompletePath, cordovaConfig) 148 | api.exitLog(`Updated ${configPath}`) 149 | } 150 | }) 151 | } 152 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const spawn = require('cross-spawn') 2 | const { info, error } = require('@vue/cli-shared-utils') 3 | const fs = require('fs') 4 | const portfinder = require('portfinder') 5 | const address = require('address') 6 | const defaults = require('./defaults') 7 | const defaultServe = require('./default-serve') 8 | 9 | const defaultModes = { 10 | 'cordova-serve-android': 'development', 11 | 'cordova-build-android': 'production', 12 | 'cordova-serve-ios': 'development', 13 | 'cordova-build-ios': 'production', 14 | 'cordova-serve-browser': 'development', 15 | 'cordova-build-browser': 'production', 16 | 'cordova-serve-osx': 'development', 17 | 'cordova-build-osx': 'production', 18 | 'cordova-serve-electron': 'development', 19 | 'cordova-build-electron': 'production', 20 | 'cordova-build-only-www-ios': 'production', 21 | 'cordova-build-only-www-android': 'production', 22 | 'cordova-build-only-www-browser': 'production', 23 | 'cordova-build-only-www-osx': 'production', 24 | 'cordova-build-only-www-electron': 'production', 25 | 'cordova-prepare': 'production' 26 | } 27 | 28 | module.exports = (api, options) => { 29 | const cordovaPath = options.pluginOptions.cordovaPath || defaults.cordovaPath 30 | const srcCordovaPath = api.resolve(cordovaPath) 31 | 32 | const getPlatformPath = platform => { 33 | return api.resolve(`${cordovaPath}/platforms/${platform}`) 34 | } 35 | 36 | const getPlatformPathWWW = platform => { 37 | return api.resolve(`${cordovaPath}/platforms/${platform}/platform_www`) 38 | } 39 | 40 | const getCordovaPathConfig = platform => { 41 | let cordovaConfigPathToUpdate 42 | if (platform === 'android') { 43 | cordovaConfigPathToUpdate = 'app/src/main/res/xml/config.xml' 44 | } else if (platform === 'ios' || platform === 'osx') { 45 | const cordovaConfigPath = api.resolve(`${cordovaPath}/config.xml`) 46 | const cordovaConfig = fs.readFileSync(cordovaConfigPath, 'utf-8') 47 | const regexAppName = /\s+(.*)<\/name>/ 48 | const appNameMatch = cordovaConfig.match(regexAppName) 49 | if (appNameMatch.length >= 3) { 50 | const appName = appNameMatch[2] 51 | cordovaConfigPathToUpdate = `${appName}/config.xml` 52 | } else { 53 | error('Unable to detect AppName!') 54 | } 55 | } else { 56 | cordovaConfigPathToUpdate = 'config.xml' 57 | } 58 | return api.resolve(`${cordovaPath}/platforms/${platform}/${cordovaConfigPathToUpdate}`) 59 | } 60 | 61 | const cordovaRun = (platform, target) => { 62 | // cordova run platform 63 | info(`executing "cordova run ${platform}" in folder ${srcCordovaPath}`) 64 | 65 | let runCommands 66 | if (target) { 67 | runCommands = [ 68 | 'run', 69 | platform, 70 | '--target', 71 | `${target}` 72 | ] 73 | } 74 | else { 75 | runCommands =[ 76 | 'run', 77 | platform 78 | ] 79 | } 80 | 81 | return spawn.sync('cordova', runCommands, { 82 | cwd: srcCordovaPath, 83 | env: process.env, 84 | stdio: 'inherit', // pipe to console 85 | encoding: 'utf-8' 86 | }) 87 | } 88 | 89 | const cordovaPrepare = () => { 90 | // cordova run platform 91 | info(`executing "cordova prepare in folder ${srcCordovaPath}`) 92 | return spawn.sync('cordova', [ 93 | 'prepare' 94 | ], { 95 | cwd: srcCordovaPath, 96 | env: process.env, 97 | stdio: 'inherit', // pipe to console 98 | encoding: 'utf-8' 99 | }) 100 | } 101 | 102 | const cordovaBuild = (platform, release = true) => { 103 | // cordova run platform 104 | const cordovaMode = release ? '--release' : '--debug' 105 | info(`executing "cordova build ${platform} ${cordovaMode}" in folder ${srcCordovaPath}`) 106 | return spawn.sync('cordova', [ 107 | 'build', 108 | platform, 109 | cordovaMode 110 | ], { 111 | cwd: srcCordovaPath, 112 | env: process.env, 113 | stdio: 'inherit', // pipe to console 114 | encoding: 'utf-8' 115 | }) 116 | } 117 | 118 | const cordovaClean = (platform) => { 119 | // cordova clean 120 | info(`executing "cordova clean ${platform}" in folder ${srcCordovaPath}`) 121 | return spawn.sync('cordova', [ 122 | 'clean', 123 | platform 124 | ], { 125 | cwd: srcCordovaPath, 126 | env: process.env, 127 | stdio: 'inherit', // pipe to console 128 | encoding: 'utf-8' 129 | }) 130 | } 131 | 132 | const cordovaJSMiddleware = platform => { 133 | return (req, res, next) => { 134 | if (req.url !== '/') { 135 | const filePath = getPlatformPathWWW(platform) + req.url 136 | try { 137 | if (fs.existsSync(filePath)) { 138 | const fileContent = fs.readFileSync(filePath, 'utf-8') 139 | res.send(fileContent) 140 | return 141 | } 142 | } catch (err) { 143 | } 144 | } 145 | next() 146 | } 147 | } 148 | 149 | const runServe = async (platform, args) => { 150 | const availablePlatforms = [] 151 | const platforms = defaults.platforms 152 | 153 | platforms.forEach(platform => { 154 | const platformPath = getPlatformPath(platform) 155 | if (fs.existsSync(platformPath)) { 156 | availablePlatforms.push(platform) 157 | } 158 | }) 159 | 160 | if (availablePlatforms.includes(platform)) { 161 | // add cordova.js, define process.env.CORDOVA_PLATFORM 162 | chainWebPack(platform) 163 | // Add js middleware 164 | configureDevServer(platform) 165 | 166 | const projectDevServerOptions = options.devServer || {} 167 | // resolve server options 168 | const open = false // browser does not need to be opened 169 | const https = options.devServer.https === null || options.devServer.https === undefined ? true : options.devServer.https // check devServer.options for user defined https setting 170 | const protocol = https ? 'https' : 'http' 171 | const host = args.host || process.env.HOST || projectDevServerOptions.host || defaultServe.host 172 | let port = args.port || process.env.PORT || projectDevServerOptions.port || defaultServe.port 173 | portfinder.basePort = port 174 | port = await portfinder.getPortPromise() 175 | const publicArg = args.public || projectDevServerOptions.public 176 | const defaultPublicURL = `${protocol}://${address.ip()}:${port}` 177 | const rawPublicUrl = publicArg || defaultPublicURL 178 | const publicUrl = rawPublicUrl 179 | ? /^[a-zA-Z]+:\/\//.test(rawPublicUrl) 180 | ? rawPublicUrl 181 | : `${protocol}://${rawPublicUrl}` 182 | : null 183 | 184 | const serveArgs = { 185 | open, 186 | host, 187 | port, 188 | https, 189 | public: publicArg 190 | } 191 | 192 | const target = args.target 193 | 194 | // npm run serve 195 | const server = await api.service.run('serve', serveArgs) 196 | 197 | // set content url to devServer 198 | process.env.CORDOVA_WEBVIEW_SRC = publicUrl 199 | process.env.CORDOVA_PREPARE_CONFIG = getCordovaPathConfig(platform) 200 | 201 | cordovaClean(platform) 202 | 203 | cordovaRun(platform, target) 204 | 205 | return server 206 | } else { 207 | if (availablePlatforms.length === 0) { 208 | error(`No platforms installed in '${srcCordovaPath}', please execute "cordova platform add ${platform}" in ${srcCordovaPath}`) 209 | } else { 210 | error(`Missing platform '${platform}', please execute "cordova platform add ${platform}" in ${srcCordovaPath}`) 211 | } 212 | } 213 | } 214 | 215 | const runBuild = async (platform, args) => { 216 | // build WWW 217 | await runWWWBuild(platform, args) 218 | // cordova clean 219 | await cordovaClean(platform) 220 | // cordova build --release (if you want a build debug build, use cordovaBuild(platform, false) 221 | await cordovaBuild(platform) 222 | } 223 | 224 | const addGitIgnoreToWWW = () => { 225 | const wwwIgnorePath = api.resolve(`${cordovaPath}/www/.gitignore`) 226 | fs.writeFileSync(wwwIgnorePath, defaults.gitIgnoreContent) 227 | } 228 | 229 | const runPrepare = async (args) => { 230 | // build WWW 231 | await runWWWBuild(null, args) 232 | // add www/.gitignore again (because build will delete it) 233 | addGitIgnoreToWWW() 234 | // cordova prepare 235 | await cordovaPrepare() 236 | } 237 | 238 | const runWWWBuild = async (platform, args) => { 239 | // add cordova.js, define process.env.CORDOVA_PLATFORM 240 | chainWebPack(platform) 241 | // set build output folder 242 | args.dest = cordovaPath + '/www' 243 | // build 244 | await api.service.run('build', args) 245 | // add www/.gitignore again (because build will delete it) 246 | addGitIgnoreToWWW() 247 | } 248 | 249 | const configureDevServer = platform => { 250 | api.configureDevServer(app => { 251 | // /cordova.js should resolve to platform cordova.js 252 | app.use(cordovaJSMiddleware(platform)) 253 | }) 254 | } 255 | 256 | const chainWebPack = platform => { 257 | api.chainWebpack(webpackConfig => { 258 | // add cordova.js to index.html 259 | webpackConfig.plugin('cordova') 260 | .use(require('html-webpack-include-assets-plugin'), [{ 261 | assets: 'cordova.js', 262 | append: false, 263 | publicPath: options.publicPath !== undefined ? options.publicPath : false 264 | }]) 265 | 266 | // process.env.CORDOVA_PLATFORM = platform 267 | if (platform !== null) { 268 | webpackConfig.plugin('define') 269 | .tap(args => { 270 | const { 'process.env': env, ...rest } = args[0] 271 | return [{ 272 | 'process.env': Object.assign( 273 | {}, 274 | env, 275 | { 276 | CORDOVA_PLATFORM: '\'' + platform + '\'' 277 | } 278 | ), 279 | ...rest 280 | }] 281 | }) 282 | } 283 | }) 284 | } 285 | 286 | api.registerCommand('cordova-serve-android', async args => { 287 | return await runServe('android', args) 288 | }) 289 | 290 | api.registerCommand('cordova-build-android', async args => { 291 | return await runBuild('android', args) 292 | }) 293 | 294 | api.registerCommand('cordova-serve-ios', async args => { 295 | return await runServe('ios', args) 296 | }) 297 | 298 | api.registerCommand('cordova-build-ios', async args => { 299 | return await runBuild('ios', args) 300 | }) 301 | 302 | api.registerCommand('cordova-serve-osx', async args => { 303 | return await runServe('osx', args) 304 | }) 305 | 306 | api.registerCommand('cordova-build-osx', async args => { 307 | return await runBuild('osx', args) 308 | }) 309 | 310 | api.registerCommand('cordova-serve-electron', async args => { 311 | return await runServe('electron', args) 312 | }) 313 | 314 | api.registerCommand('cordova-build-electron', async args => { 315 | return await runBuild('electron', args) 316 | }) 317 | 318 | api.registerCommand('cordova-build-only-www-ios', async args => { 319 | return await runWWWBuild('ios', args) 320 | }) 321 | 322 | api.registerCommand('cordova-build-only-www-android', async args => { 323 | return await runWWWBuild('android', args) 324 | }) 325 | 326 | api.registerCommand('cordova-build-only-www-browser', async args => { 327 | return await runWWWBuild('browser', args) 328 | }) 329 | 330 | api.registerCommand('cordova-build-only-www-osx', async args => { 331 | return await runWWWBuild('osx', args) 332 | }) 333 | 334 | api.registerCommand('cordova-build-only-www-electron', async args => { 335 | return await runWWWBuild('electron', args) 336 | }) 337 | 338 | api.registerCommand('cordova-prepare', async args => { 339 | return await runPrepare(args) 340 | }) 341 | 342 | api.registerCommand('cordova-serve-browser', async args => { 343 | args.open = true 344 | const platform = 'browser' 345 | chainWebPack(platform) 346 | configureDevServer(platform) 347 | return await api.service.run('serve', args) 348 | }) 349 | api.registerCommand('cordova-build-browser', async args => { 350 | return await runBuild('browser', args) 351 | }) 352 | } 353 | 354 | module.exports.defaultModes = defaultModes 355 | --------------------------------------------------------------------------------