commit 722c0042e58dddcdb26f686cc23933c8a1ebe72b Author: Knut Ahlers Date: Fri Dec 3 17:54:08 2021 +0100 Initial version diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bce361a --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) [year] [fullname] + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d9610f --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Luzifer / cc-esbuild-vue + +This repository contains a [cookiecutter](https://github.com/cookiecutter/cookiecutter) project template for a Vue.js / ESBuild single-page application. + +It can be initialized into a new project as follows: + +```console +# cookiecutter gh:Luzifer/cc-esbuild-vue +folder_name [myfolder]: +main_component_name [MyFolder]: +output_folder_name [public]: + +# l --tree myfolder +drwxr-xr-x - luzifer luzifer 3 Dec 17:52 myfolder +drwxr-xr-x - luzifer luzifer 3 Dec 17:52 ├── ci +.rw-r--r-- 404 luzifer luzifer 3 Dec 17:52 │ └── build.mjs +.rw-r--r-- 168 luzifer luzifer 3 Dec 17:52 ├── Makefile +.rw-r--r-- 350 luzifer luzifer 3 Dec 17:52 ├── package.json +drwxr-xr-x - luzifer luzifer 3 Dec 17:52 ├── public +.rw-r--r-- 380 luzifer luzifer 3 Dec 17:52 │ └── index.html +drwxr-xr-x - luzifer luzifer 3 Dec 17:52 └── src +.rw-r--r-- 95 luzifer luzifer 3 Dec 17:52 ├── app.vue +.rw-r--r-- 436 luzifer luzifer 3 Dec 17:52 └── main.js +``` + +Afterwards have a look at the `src` files, the `Makefile`, the `ci/build.mjs` and the `package.json` for further usage. diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..9be5392 --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,5 @@ +{ + "folder_name": "myfolder", + "main_component_name": "MyFolder", + "output_folder_name": "public" +} diff --git a/{{cookiecutter.folder_name}}/.eslintrc.js b/{{cookiecutter.folder_name}}/.eslintrc.js new file mode 100644 index 0000000..c2d2368 --- /dev/null +++ b/{{cookiecutter.folder_name}}/.eslintrc.js @@ -0,0 +1,151 @@ +/* + * Hack to automatically load globally installed eslint modules + * on Archlinux systems placed in /usr/lib/node_modules + * + * Source: https://github.com/eslint/eslint/issues/11914#issuecomment-569108633 + */ + +const Module = require('module') + +const hacks = [ + 'babel-eslint', + 'eslint-plugin-vue', +] + +const ModuleFindPath = Module._findPath +Module._findPath = (request, paths, isMain) => { + const r = ModuleFindPath(request, paths, isMain) + if (!r && hacks.includes(request)) { + return require.resolve(`/usr/lib/node_modules/${request}`) + } + return r +} + +/* + * ESLint configuration derived as differences from eslint:recommended + * with changes I found useful to ensure code quality and equal formatting + * https://eslint.org/docs/user-guide/configuring + */ + +module.exports = { + env: { + browser: true, + node: true, + }, + + extends: [ + 'plugin:vue/recommended', + 'eslint:recommended', // https://eslint.org/docs/rules/ + ], + + globals: { + process: true, + }, + + parserOptions: { + ecmaVersion: 2020, + parser: 'babel-eslint', + }, + + plugins: [ + // required to lint *.vue files + 'vue', + ], + + reportUnusedDisableDirectives: true, + + root: true, + + rules: { + 'array-bracket-newline': ['error', { multiline: true }], + 'array-bracket-spacing': ['error'], + 'arrow-body-style': ['error', 'as-needed'], + 'arrow-parens': ['error', 'as-needed'], + 'arrow-spacing': ['error', { after: true, before: true }], + 'block-spacing': ['error'], + 'brace-style': ['error', '1tbs'], + 'camelcase': ['error'], + 'comma-dangle': ['error', 'always-multiline'], + 'comma-spacing': ['error'], + 'comma-style': ['error', 'last'], + 'curly': ['error'], + 'default-case-last': ['error'], + 'default-param-last': ['error'], + 'dot-location': ['error', 'property'], + 'dot-notation': ['error'], + 'eol-last': ['error', 'always'], + 'eqeqeq': ['error', 'always', { null: 'ignore' }], + 'func-call-spacing': ['error', 'never'], + 'function-paren-newline': ['error', 'multiline'], + 'generator-star-spacing': ['off'], // allow async-await + 'implicit-arrow-linebreak': ['error'], + 'indent': ['error', 2], + 'key-spacing': ['error', { afterColon: true, beforeColon: false, mode: 'strict' }], + 'keyword-spacing': ['error'], + 'linebreak-style': ['error', 'unix'], + 'lines-between-class-members': ['error'], + 'multiline-comment-style': ['warn'], + 'newline-per-chained-call': ['error'], + 'no-alert': ['error'], + 'no-console': ['off'], + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', // allow debugger during development + 'no-duplicate-imports': ['error'], + 'no-else-return': ['error'], + 'no-empty-function': ['error'], + 'no-extra-parens': ['error'], + 'no-implicit-coercion': ['error'], + 'no-lonely-if': ['error'], + 'no-multi-spaces': ['error'], + 'no-multiple-empty-lines': ['warn', { max: 2, maxBOF: 0, maxEOF: 0 }], + 'no-promise-executor-return': ['error'], + 'no-return-assign': ['error'], + 'no-script-url': ['error'], + 'no-template-curly-in-string': ['error'], + 'no-trailing-spaces': ['error'], + 'no-unneeded-ternary': ['error'], + 'no-unreachable-loop': ['error'], + 'no-unsafe-optional-chaining': ['error'], + 'no-useless-return': ['error'], + 'no-var': ['error'], + 'no-warning-comments': ['error'], + 'no-whitespace-before-property': ['error'], + 'object-curly-newline': ['error', { consistent: true }], + 'object-curly-spacing': ['error', 'always'], + 'object-shorthand': ['error'], + 'padded-blocks': ['error', 'never'], + 'prefer-arrow-callback': ['error'], + 'prefer-const': ['error'], + 'prefer-object-spread': ['error'], + 'prefer-rest-params': ['error'], + 'prefer-template': ['error'], + 'quote-props': ['error', 'consistent-as-needed', { keywords: false }], + 'quotes': ['error', 'single', { allowTemplateLiterals: true }], + 'require-atomic-updates': ['error'], + 'require-await': ['error'], + 'semi': ['error', 'never'], + 'sort-imports': ['error', { ignoreCase: true, ignoreDeclarationSort: false, ignoreMemberSort: false }], + 'sort-keys': ['error', 'asc', { caseSensitive: true, natural: false }], + 'space-before-blocks': ['error', 'always'], + 'space-before-function-paren': ['error', 'never'], + 'space-in-parens': ['error', 'never'], + 'space-infix-ops': ['error'], + 'space-unary-ops': ['error', { nonwords: false, words: true }], + 'spaced-comment': ['warn', 'always'], + 'switch-colon-spacing': ['error'], + 'template-curly-spacing': ['error', 'never'], + 'unicode-bom': ['error', 'never'], + 'vue/new-line-between-multi-line-property': ['error'], + 'vue/no-empty-component-block': ['error'], + 'vue/no-reserved-component-names': ['error'], + 'vue/no-template-target-blank': ['error'], + 'vue/no-unused-properties': ['error'], + 'vue/no-unused-refs': ['error'], + 'vue/no-useless-mustaches': ['error'], + 'vue/order-in-components': ['off'], // Collides with sort-keys + 'vue/require-name-property': ['error'], + 'vue/v-for-delimiter-style': ['error'], + 'vue/v-on-function-call': ['error'], + 'wrap-iife': ['error'], + 'yoda': ['error'], + }, +} diff --git a/{{cookiecutter.folder_name}}/Makefile b/{{cookiecutter.folder_name}}/Makefile new file mode 100644 index 0000000..a61f75d --- /dev/null +++ b/{{cookiecutter.folder_name}}/Makefile @@ -0,0 +1,13 @@ +default: lint build + +build: node_modules + node ci/build.mjs + +lint: node_modules + ./node_modules/.bin/eslint \ + --ext .js,.vue \ + --fix \ + src + +node_modules: + npm ci diff --git a/{{cookiecutter.folder_name}}/ci/build.mjs b/{{cookiecutter.folder_name}}/ci/build.mjs new file mode 100644 index 0000000..5986edc --- /dev/null +++ b/{{cookiecutter.folder_name}}/ci/build.mjs @@ -0,0 +1,21 @@ +import vuePlugin from 'esbuild-vue' +import esbuild from 'esbuild' + +esbuild.build({ + bundle: true, + define: { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'dev'), + }, + entryPoints: ['src/main.js'], + loader: {}, + minify: true, + outfile: '{{cookiecutter.output_folder_name}}/app.js', + plugins: [vuePlugin()], + target: [ + 'chrome87', + 'edge87', + 'es2020', + 'firefox84', + 'safari14', + ], +}) diff --git a/{{cookiecutter.folder_name}}/package.json b/{{cookiecutter.folder_name}}/package.json new file mode 100644 index 0000000..763df05 --- /dev/null +++ b/{{cookiecutter.folder_name}}/package.json @@ -0,0 +1,16 @@ +{ + "devDependencies": { + "babel-eslint": "^10.1.0", + "esbuild": "^0.8.43", + "esbuild-vue": "^0.4.0", + "eslint": "^7.19.0", + "eslint-plugin-vue": "^7.20.0", + "vue-template-compiler": "^2.6.14" + }, + "dependencies": { + "bootstrap": "^4.6.0", + "bootstrap-vue": "^2.21.2", + "bootswatch": "^4.6.0", + "vue": "^2.6.14" + } +} diff --git a/{{cookiecutter.folder_name}}/src/app.vue b/{{cookiecutter.folder_name}}/src/app.vue new file mode 100644 index 0000000..741d202 --- /dev/null +++ b/{{cookiecutter.folder_name}}/src/app.vue @@ -0,0 +1,9 @@ + + + diff --git a/{{cookiecutter.folder_name}}/src/main.js b/{{cookiecutter.folder_name}}/src/main.js new file mode 100644 index 0000000..050437b --- /dev/null +++ b/{{cookiecutter.folder_name}}/src/main.js @@ -0,0 +1,20 @@ +/* eslint-disable sort-imports */ + +import 'bootstrap/dist/css/bootstrap.css' +import 'bootstrap-vue/dist/bootstrap-vue.css' +import 'bootswatch/dist/darkly/bootstrap.css' + +import Vue from 'vue' +import { BootstrapVue } from 'bootstrap-vue' + +import App from './app.vue' + +Vue.config.devtools = process.env.NODE_ENV === 'dev' +Vue.use(BootstrapVue) + +new Vue({ + components: { App }, + el: '#app', + name: '{{ cookiecutter.main_component_name }}', + render: h => h(App), +}) diff --git a/{{cookiecutter.folder_name}}/{{cookiecutter.output_folder_name}}/index.html b/{{cookiecutter.folder_name}}/{{cookiecutter.output_folder_name}}/index.html new file mode 100644 index 0000000..72529da --- /dev/null +++ b/{{cookiecutter.folder_name}}/{{cookiecutter.output_folder_name}}/index.html @@ -0,0 +1,18 @@ + + + + + {{ cookiecutter.main_component_name }} + + + + + + +
+ + + +