Initial version

This commit is contained in:
Knut Ahlers 2021-12-03 17:54:08 +01:00
commit 722c0042e5
Signed by: luzifer
GPG key ID: 0066F03ED215AD7D
10 changed files with 301 additions and 0 deletions

22
LICENSE Normal file
View file

@ -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.

26
README.md Normal file
View file

@ -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.

5
cookiecutter.json Normal file
View file

@ -0,0 +1,5 @@
{
"folder_name": "myfolder",
"main_component_name": "MyFolder",
"output_folder_name": "public"
}

View file

@ -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'],
},
}

View file

@ -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

View file

@ -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',
],
})

View file

@ -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"
}
}

View file

@ -0,0 +1,9 @@
<template>
<div />
</template>
<script>
export default {
name: '{{ cookiecutter.main_component_name }}App',
}
</script>

View file

@ -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),
})

View file

@ -0,0 +1,18 @@
<!doctype html>
<html lang="de">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{{ cookiecutter.main_component_name }}</title>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="app.css" rel="stylesheet">
<style>
[v-cloak] { display: none; }
</style>
<div id="app" v-cloak></div>
<script src="app.js"></script>
</html>