diff --git a/README.md b/README.md index 798b09a..8d50b6c 100644 --- a/README.md +++ b/README.md @@ -1 +1,30 @@ -# vue-wp-bootstrap \ No newline at end of file +# Vue WordPress Plugin Boilerplate + +### Usage + +This is a project template for [@vue/cli](https://cli.vuejs.org). + +``` bash +$ npm install -g @vue/cli +$ npm install -g @vue/cli-init +$ vue init abaicus/vue-wp-bootstrap my-project +$ cd my-project +$ composer install +$ npm install +$ npm run dev +``` + +### What's Included +- `docker-compose up`: the template comes with a preconfigured `docker-compose` file that will run a full WordPress instance. If you want to use that, you might want to look into that one first. + +- `npm run dev`: WebPack, SCSS, Eslint watching. + +- `npm run build`: WebPack, SCSS build for production. + +- `npm run lint`: Lint `.js` and `.vue` files with ESLint. +- `npm run pre-commit`: PHPCBF, PHPCS, Lint and add to git. This is ran automatically on commit if you initialize the project with commit lint. + +### Customizations +You will likely need to do some tuning to suit your own needs: + +- Install additional libraries that you need, e.g. `vue-router`, `vue-resource`, `vuex`, etc... diff --git a/meta.js b/meta.js new file mode 100644 index 0000000..6cabf8b --- /dev/null +++ b/meta.js @@ -0,0 +1,101 @@ +module.exports = { + helpers: { + lowercase: str => str.toLowerCase(), + abbreviate: str => { + if (str.indexOf('-') > -1) { + let matches = str.match(/\b(\w)/g); + return matches.join('') + .toUpperCase(); + } + return str.toUpperCase(); + }, + lowercaseAbbrev: str => { + if (str.indexOf('-') > -1) { + let matches = str.match(/\b(\w)/g); + return matches.join('') + .toLowerCase(); + } + return str.toLowerCase(); + }, + }, + 'prompts': { + 'name': { + 'type': 'string', + 'required': true, + 'label': 'Plugin Slug (Must be Hyphened)', + 'default': 'wordpress-vue-js-bootstrap' + }, + 'niceName': { + 'type': 'string', + 'required': true, + 'label': 'Plugin Nice Name', + 'default': 'WordPress Vue.js Bootstrap' + }, + 'textdomain': { + 'type': 'string', + 'required': true, + 'label': 'Plugin Text Domain', + 'default': 'textdomain' + }, + 'version': { + 'type': 'string', + 'required': true, + 'label': 'The version of the package', + 'default': '0.0.1' + }, + 'description': { + 'type': 'string', + 'required': true, + 'label': 'Project description', + 'default': 'A Vue.js WordPress Plugin' + }, + 'author': { + 'type': 'string', + 'label': 'Author' + }, + 'authorUrl': { + 'type': 'string', + 'label': 'Author URI', + 'default': 'https://themeisle.com' + }, + 'license': { + 'type': 'string', + 'label': 'License', + 'default': 'GPL-2.0+' + }, + 'licenseUrl': { + 'type': 'string', + 'label': 'License', + 'default': 'https://www.gnu.org/licenses/gpl-2.0.html' + }, + 'build': { + 'type': 'list', + 'message': 'Vue build', + 'choices': [ + { + 'name': 'Runtime + Compiler: recommended for most users', + 'value': 'standalone', + 'short': 'standalone' + }, + { + 'name': 'Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere', + 'value': 'runtime', + 'short': 'runtime' + } + ] + }, + 'lint': { + 'type': 'confirm', + 'message': 'Use ESLint to lint your code?' + }, + 'commitlint': { + 'type': 'confirm', + 'message': 'Setup Commit Lint and Pre-Commit Hooks?' + } + }, + 'filters': { + '.eslintrc.js': 'lint', + '.commitlintrc.js' : 'commitlint' + }, + 'completeMessage': 'To get started:\n\n cd {{destDirName}}\n composer install\n npm install\n npm run dev' +}; diff --git a/template/.babelrc b/template/.babelrc new file mode 100644 index 0000000..7a8bc5a --- /dev/null +++ b/template/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["env"], + "plugins": ["transform-object-rest-spread"] +} diff --git a/template/.commitlintrc.js b/template/.commitlintrc.js new file mode 100644 index 0000000..2b47d7d --- /dev/null +++ b/template/.commitlintrc.js @@ -0,0 +1,29 @@ +const Configuration = { + extends: [ '@commitlint/config-conventional' ], + rules: { + 'subject-case': [ + 2, + 'never', + ['start-case', 'pascal-case', 'upper-case'] + ], + 'type-enum': [ + 2, + 'always', + [ + 'build', + 'chore', + 'ci', + 'docs', + 'feat', + 'fix', + 'perf', + 'refactor', + 'revert', + 'style', + 'test' + ] + ] + } +}; + +module.exports = Configuration; diff --git a/template/.eslintrc b/template/.eslintrc new file mode 100644 index 0000000..89f65dc --- /dev/null +++ b/template/.eslintrc @@ -0,0 +1,9 @@ +{ + "extends": "standard", + "plugins": [ + "html" + ], + "env": { + "jasmine": true + } +} diff --git a/template/.gitignore b/template/.gitignore new file mode 100644 index 0000000..72d0900 --- /dev/null +++ b/template/.gitignore @@ -0,0 +1,11 @@ +.idea +node_modules +logs +dist +artifact +vendor +bin +composer.lock +**/*.js.map +**/*.css.map +**/.DS_Store diff --git a/template/README.md b/template/README.md new file mode 100644 index 0000000..20aef7d --- /dev/null +++ b/template/README.md @@ -0,0 +1,24 @@ +# {{ name }} + +> {{ description }} + +## Build Setup + +``` bash +# install dependencies +npm install + +# serve with hot reload at localhost:8080 +npm run dev + +# build for production with minification +npm run build + +# lint all *.js and *.vue files +npm run lint + +# run unit tests +npm test +``` + +For more information see the [docs for vueify](https://github.com/vuejs/vueify). diff --git a/template/assets/css/style.css b/template/assets/css/style.css new file mode 100644 index 0000000..e69de29 diff --git a/template/assets/css/style.css.map b/template/assets/css/style.css.map new file mode 100644 index 0000000..2d06e40 --- /dev/null +++ b/template/assets/css/style.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "file": "style.css", + "sources": [ + "../scss/style.scss" + ], + "names": [], + "mappings": "AAAA,AAAA,KAAK,CAAC;EACJ,KAAK,EAAE,IAAI;EACX,gBAAgB,EAAE,IAAI,GACvB" +} \ No newline at end of file diff --git a/template/assets/js/build.js b/template/assets/js/build.js new file mode 100644 index 0000000..e69de29 diff --git a/template/assets/scss/style.scss b/template/assets/scss/style.scss new file mode 100644 index 0000000..919de8c --- /dev/null +++ b/template/assets/scss/style.scss @@ -0,0 +1,10 @@ +.{{lowercaseAbbrev name}}-wrap { + background-color: #fff; + padding: 20px; + margin-right: 20px; + margin-top: 20px; + margin-bottom: 20px; + box-shadow: 0 0 10px -5px rgba(0,0,0,0.5); + border-radius: 3px; + text-align: center; +} diff --git a/template/assets/src/App.vue b/template/assets/src/App.vue new file mode 100644 index 0000000..8bc707e --- /dev/null +++ b/template/assets/src/App.vue @@ -0,0 +1,23 @@ +/* jshint esversion: 6 */ + + + + + diff --git a/template/assets/src/main.js b/template/assets/src/main.js new file mode 100644 index 0000000..6fce796 --- /dev/null +++ b/template/assets/src/main.js @@ -0,0 +1,11 @@ +/* jshint esversion: 6 */ +import Vue from 'vue' +import App from './App.vue' + +window.addEventListener('load', function () { + new Vue({ // eslint-disable-line no-new + el: '#{{lowercaseAbbrev name}}-app', + components: { App }, + render: (h) => h(App) + }) +}) diff --git a/template/composer.json b/template/composer.json new file mode 100644 index 0000000..dabdd03 --- /dev/null +++ b/template/composer.json @@ -0,0 +1,26 @@ +{ + "name": "codeinwp/{{slug}}", + "description": "{{description}}", + "homepage": "{{authorUrl}}", + "license": "{{license}}", + "authors": [ + { + "name": "{{author}}", + "email": "friends@themeisle.com", + "homepage": "{{authorUrl}}" + } + ], + "scripts": { + "format": "phpcbf --standard=phpcs.xml --report-summary --report-source -s --runtime-set testVersion 5.4- ", + "phpcs": "phpcs --standard=phpcs.xml -s --runtime-set testVersion 5.4-", + "lint": "composer run-script phpcs" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "extra": { + "installer-disable": "true" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0" + } +} diff --git a/template/docker-compose.yml b/template/docker-compose.yml new file mode 100644 index 0000000..a23735f --- /dev/null +++ b/template/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3.1' + +services: + wordpress: + depends_on: + - mysql + image: hardeepasrani/pirate-brewery + ports: + - 998:80 + volumes: + - ./:/var/www/html/wp-content/plugins/{{name}} + restart: always + environment: + WORDPRESS_DB_NAME: wordpress + WORDPRESS_DB_USER: wordpress + WORDPRESS_DB_PASSWORD: wordpress + WORDPRESS_DB_ROOT_PASSWORD: wordpress + mysql: + image: mysql:5.7 + volumes: + - ~/db_data{{abbreviation}}:/var/lib/mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: wordpress + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + MYSQL_PASSWORD: wordpress diff --git a/template/includes/admin.php b/template/includes/admin.php new file mode 100644 index 0000000..8c8a6c7 --- /dev/null +++ b/template/includes/admin.php @@ -0,0 +1,46 @@ +
'; + } +} diff --git a/template/includes/assets.php b/template/includes/assets.php new file mode 100644 index 0000000..d302604 --- /dev/null +++ b/template/includes/assets.php @@ -0,0 +1,66 @@ +base ) || $screen->base !== 'toplevel_page_{{lowercaseAbbrev name}}-app' ) { + return; + } + + wp_register_style( $this->handle, {{abbreviate name}}_URL . 'assets/css/style.css', [], {{abbreviate name}}_VERSION ); + wp_enqueue_style( $this->handle ); + + wp_register_script( $this->handle, {{abbreviate name}}_URL . 'assets/js/build.js', [], {{abbreviate name}}_VERSION, true ); + wp_localize_script( $this->handle, '{{abbreviate name}}', $this->app_localization() ); + wp_enqueue_script( $this->handle ); + } + + /** + * Localize main application script. + * + * @access private + * @return array + */ + private function app_localization() { + return [ + 'strings' => [ + 'title' => 'Hello from VUE.JS', + 'description' => 'This text is passed through the {{abbreviate name}} localized object.', + ], + ]; + } +} diff --git a/template/includes/rest.php b/template/includes/rest.php new file mode 100644 index 0000000..9d97b25 --- /dev/null +++ b/template/includes/rest.php @@ -0,0 +1,41 @@ +namespace = '{{lowercaseAbbrev name}}/v1'; + add_action( 'rest_api_init', [ $this, 'register_routes' ] ); + } + + /** + * Register rest routes. + * + * @access public + * @hooked `rest_api_init` + * @return void + */ + public function register_routes() {} +} diff --git a/template/package.json b/template/package.json new file mode 100644 index 0000000..537665e --- /dev/null +++ b/template/package.json @@ -0,0 +1,71 @@ +{ + "name": "{{ name }}", + "version": "{{ version }}", + "description": "{{ description }}", + "author": "{{ author }}", + "scripts": { + "build": "npm-run-all --parallel build:js build:css", + "dev": "npm-run-all --parallel watch:js{{#lint}} watch:eslint{{/lint}} watch:css", + {{#lint}} + "lint": "eslint --ext .js,.vue assets/src", + "watch:eslint": "esw -w --ext .js,.vue assets/src --color", + {{/lint}} + "watch:js": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", + "watch:css": "./node_modules/.bin/node-sass --watch assets/scss -o assets/css --source-map true", + "build:js": "cross-env NODE_ENV=production webpack --progress --hide-modules", + "phpcbf": "composer run-script format || true ", + "phpcs": "composer run-script phpcs", + "build:css": "node-sass assets/scss -o assets/css"{{#commitlint}}, + "git:add": "git add assets/**/*", + "pre-commit": "npm-run-all phpcbf phpcs lint build git:add" + {{/commitlint}} + }, + {{#if_eq build "standalone"}} + "browser": { + "vue": "vue/dist/vue.common.js" + }, + {{/if_eq}} + "dependencies": { + "vue": "^2.6.10" + }, + "devDependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.2", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.7.0", + {{#commitlint}} + "@commitlint/cli": "^7.2.1", + "@commitlint/config-conventional": "^7.1.2", + {{/commitlint}} + "cross-env": "^3.2.4", + "css-loader": "^0.28.7", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.4", + "style-loader": "^0.23.1", + "uglifyjs-webpack-plugin": "^1.2.5", + "vue-loader": "^14.2.4", + "vue-template-compiler": "^2.4.4", + {{#lint}} + "eslint": "^3.3.0", + "eslint-config-standard": "^5.3.5", + "eslint-plugin-html": "^1.5.2", + "eslint-plugin-promise": "^2.0.1", + "eslint-plugin-standard": "^2.0.0", + "eslint-watch": "^5.0.1", + {{/lint}} + {{#commitlint}} + "husky": "^1.2.0", + {{/commitlint}} + "node-sass": "^4.11.0", + "npm-run-all": "^2.3.0", + "webpack": "^3.12.0" + }{{#commitlint}}, + "husky": { + "hooks": { + "pre-commit": "npm run pre-commit", + "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" + } + } + {{/commitlint}} +} diff --git a/template/phpcs.xml b/template/phpcs.xml new file mode 100644 index 0000000..81a8ca5 --- /dev/null +++ b/template/phpcs.xml @@ -0,0 +1,36 @@ + + + Themeisle rules for PHP_CodeSniffer + + . + + node_modules/* + vendor/* + tests/* + *.min.js + *.min.css + *.js + *.css + + + + + + + + + + + + + + + + + + + + 0 + + + diff --git a/template/plugin.php b/template/plugin.php new file mode 100644 index 0000000..d115f34 --- /dev/null +++ b/template/plugin.php @@ -0,0 +1,111 @@ +define_constants(); + $instance->run(); + } + + return $instance; + } + + /** + * Define the plugins constants. + * + * @access public + * @return void + */ + public function define_constants() { + define( '{{abbreviate name}}_VERSION', $this->version ); + define( '{{abbreviate name}}_FILE', __FILE__ ); + define( '{{abbreviate name}}_PATH', dirname( {{abbreviate name}}_FILE ) ); + define( '{{abbreviate name}}_INCLUDES', {{abbreviate name}}_PATH . '/includes' ); + define( '{{abbreviate name}}_URL', trailingslashit( plugins_url( '', {{abbreviate name}}_FILE ) ) ); + } + + /** + * Initialize the plugins main components. + * + * @access private + * @return void + */ + private function run() { + require_once {{abbreviate name}}_INCLUDES . '/admin.php'; + require_once {{abbreviate name}}_INCLUDES . '/rest.php'; + require_once {{abbreviate name}}_INCLUDES . '/assets.php'; + + $this->entities['admin'] = new Admin(); + $this->entities['server'] = new Rest(); + $this->entities['assets'] = new Assets(); + } + + /** + * Get plugin version. + * + * @access public + * @return string + */ + public function get_version() { + return $this->version; + } + + /** + * Get plugin components instances. + * + * @access public + * @return array + */ + public function get_components() { + return $this->entities; + } +} + +Plugin::get_instance(); diff --git a/template/webpack.config.js b/template/webpack.config.js new file mode 100644 index 0000000..949a8d6 --- /dev/null +++ b/template/webpack.config.js @@ -0,0 +1,112 @@ +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const webpack = require('webpack'); +const path = require('path'); +const env = process.env.NODE_ENV; +const plugins = []; + +if (env === 'production') { + const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin; + plugins.push(new UglifyJsPlugin({ minimize: true })); + plugins.push( + new webpack.DefinePlugin( + { + 'process.env': { + NODE_ENV: '"production"' + } + } + ) + ); +} + +module.exports = { + entry: { + 'build': ['./assets/src/main.js'] + }, + stats: { warnings: false }, // Hide warnings + output: { + path: path.resolve(__dirname, 'assets/js'), + filename: '[name].js' + }, + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + options: { + loaders: { + // Since sass-loader (weirdly) has SCSS as its default parse mode, we map + // the "scss" and "sass" values for the lang attribute to the right configs here. + // other preprocessors should work out of the box, no loader config like this necessary. + scss: 'vue-style-loader!css-loader!sass-loader', + sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' + } + } + }, + { + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader', + options: { + presets: [ + [ + 'env', + { + targets: { + browsers: [ + 'Chrome >= 52', + 'FireFox >= 44', + 'Safari >= 7', + 'Explorer 11', + 'last 4 Edge versions' + ] + }, + useBuiltIns: true + } + ] + ] + } + } + }, + { + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { importLoaders: 1 } + }, + 'postcss-loader' + ] + }) + }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + { + loader: 'file-loader', + options: { + name: 'img/[name].[ext]' + } + } + ] + }, + { + test: /\.(png|woff|woff2|eot|ttf|svg)$/, + use: { + loader: 'file-loader', + options: { + name: 'fonts/[name].[ext]' + } + } + } + ] + }, + resolve: { + alias: { + vue$: 'vue/dist/vue.esm.js' + } + }, + plugins +};