Skip to content

CodeCoupler Webpack Development Details: Boilerplate Files

All the files of the boilerplate explained:

.vscode/settings.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{

  //Tell VSCode what type some files are:
  "files.associations": {
    "*.postcssrc": "json",
    "*.lintstagedrc": "json"
  },

  //Disable built-In Validators and let only stylelint validate and fix:
  "css.validate": false,
  "less.validate": false,
  "scss.validate": false,

  //Enable prettier, eslint and stylelint with automatic fix. By default only JavaScript files
  //will be linted. This enabled linting for typescript files.
  //No fix on save with auto "files.autoSave=on":
  "eslint.enable": true,
  "stylelint.enable": true,
  "files.autoSave": "off",
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true,
    "source.fixAll.markdownlint": true
  },

  //To avoid validation from any TSLint installation:
  "tslint.enable": false,

  //Enable automatic fix for prettier extension:
  "editor.formatOnSave": true

  //Unify tab sizes
  "editor.tabSize": 2,

  //Unify EOL
  "files.eol": "\n"

  //Enable linting for vue files
  "vetur.validation.template": false,
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "vue"
  ]

  //This is recommended to prevent running 2 formatting commands
  //on save for JavaScript and TypeScript files, but this will
  //disable automatic fixing at all. So this will *not* be used:
  // "[javascript]": {
  //   "editor.formatOnSave": false
  // },
  // "[javascriptreact]": {
  //   "editor.formatOnSave": false
  // },
  // "[typescript]": {
  //   "editor.formatOnSave": false
  // },
  // "[typescriptreact]": {
  //   "editor.formatOnSave": false
  // }

}

.eslintrc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{

  // Starting with the global configuration for all JavaScript Files

  "extends": [
    // Set of rules which are recommended for all projects by the ESLint Team
    "eslint:recommended",
    // Rules for Vue validation
    "plugin:vue/recommended",
    // Enables eslint-plugin-prettier and eslint-config-prettier.
    // Turns off all rules that are unnecessary or might conflict with Prettier
    // This will display prettier errors as ESLint errors.
    // Make sure this is always the last configuration in the extends array.
    "plugin:prettier/recommended"
  ],
  // Normally we have here to use babel as parser to recognize experimental features.
  // But "vue-eslint-parser" have to be in first place. Therefore the babel parser is
  // moved into "parserOptions.parser".
  "parser": "vue-eslint-parser"
  "parserOptions": {
    // Parser to used internally by "vue-eslint-parser"
    "parser": "@babel/eslint-parser",
    // Using version 11 to allow dynamic imports and implement lazy loading
    "ecmaVersion": 11,
    "sourceType": "module",
    // For linting files that are not transformed by Babel (such as tooling configuration files)
    "requireConfigFile": false
  },
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  // Plugins for parser and formatting rules
  "plugins": ["babel", "prettier"],
  "rules": {
    "prettier/prettier": "error",
    //This one was added because eslint cannot handle private methods for now.
    //The error "Duplicate name ''  no-dupe-class-members" occurs.
    //If Babel 8 will be released this can be removed.
    "no-dupe-class-members": "off"
  },

  // Now override special configuration for TypeScript Files

  "overrides": [
    {
      "files": ["**/*.ts"],
      // Specifies the ESLint parser that will allow ESLint to lint TypeScript code
      "parser": "@typescript-eslint/parser",
      "extends": [
        // set of rules which are recommended for all projects by the ESLint Team
        "eslint:recommended",
        // Turns off all rules that are unnecessary or might conflict with Prettier
        "plugin:@typescript-eslint/eslint-recommended",
        // Uses the recommended rules from the @typescript-eslint/eslint-plugin
        "plugin:@typescript-eslint/recommended",
        // Enables eslint-plugin-prettier and eslint-config-prettier.
        // This will display prettier errors as ESLint errors.
        // Make sure this is always the last configuration in the extends array.
        "plugin:prettier/recommended"
      ],
      "parserOptions": {
        // Using version 11 to allow dynamic imports and implement lazy loading
        "ecmaVersion": 11,
        "sourceType": "module"
      },
      "env": {
        "browser": true,
        "node": true,
        "es6": true
      },
      "plugins": [
        // A plugin that contains a bunch of ESLint rules that are TypeScript specific
        "@typescript-eslint/eslint-plugin",
        // Plugin with formatting rules
        "prettier"
      ],
      "rules": {
        "prettier/prettier": "error"
      }
    }
  ]
}

.prettierc

The "trailingComma" was done to align the rules of the eslint-prettier-plugin rules and the default prettier rules used by the IDE on save.

The override for markdown files was done to align the rules of prettier with the settings of .markdownlint.json. Furthermore with proseWrap we enable automatic wrapping in markdown files.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "trailingComma": "none",
  "overrides": [
    {
      "files": "*.md",
      "options": {
        "printWidth": 100,
        "proseWrap": "always"
      }
    }
  ]
}

.markdownlint.json

1
2
3
4
5
6
{
  // This rule is disabled by default, because lines are often longer than 80 chars. But the markdown
  // looks odd has long lines and short lines distributed unevenly. Maybe a line length of 100 is a better
  // approach:
  "MD013": { "line_length": 100 }
}

.postcssrc

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "plugins": {
    // You could ask at this point why we need "postcss-import" since we already use css-loader
    // after PostCSS. Both will follow @import rules and inline the code. The reason is that PostCSS
    // do some more things with the inlined CSS as css-loader. Without this plugin the imported CSS
    // will not compiled for the targeted browsers, prefixed and so on. On the other hand we need
    // css-loader for including url() statements.
    "postcss-import": {},
    // Compile modern CSS for targeted browsers
    "postcss-preset-env": {},
    // Prefix CSS for targeted browsers
    "autoprefixer": {},
    // Mangle and minify CSS
    "cssnano": {}
  }
}

.stylelintrc

1
2
3
4
5
6
7
8
{
  // This configuration turns off all rules that might conflict with Prettier
  "extends": ["stylelint-config-standard","stylelint-prettier/recommended"],
  "plugins": ["stylelint-prettier"],
  "rules": {
    "prettier/prettier": true
  }
}

tsconfig.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  "compilerOptions": {
    // The directory for the output
    // Is this needed? Maybe because it will be automatically set as "exclude" glob.
    "outDir": "./dist/",
    // Is this needed?
    "noImplicitAny": true,
    // Without this (or with another value like "es6") we cannot use 'import "a-node-library"' from
    // TypeScript files.
    "module": "commonjs",
    // Enable Decorators for class style vue apps
    "experimentalDecorators": true,
    // As we use babel this maybe is not needed, or other values acceptable.
    // From Vue.js docs: This aligns with Vue's browser support
    "target": "es5",
    // Create source maps in combination with "devtool"
    "sourceMap": true,
    // From Vue.js docs:
    // This enables stricter inference for data properties on `this`.
    // Note that you have to include strict: true (or at least noImplicitThis: true which is a part
    // of strict flag) to leverage type checking of this in component methods otherwise it is always
    // treated as any type.
    "strict": true
    // Vue.js docs note this two settings, but they are not used here:
    // If using webpack 2+ or rollup, to leverage tree shaking:
    // "module": "es2015",
    // "moduleResolution": "node"
  }
}

.gitignore

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Dependency directories
node_modules/

# Transpiled source files
dist/

# Compiled documentation
site/

# Cache used by TypeScript's incremental build
*.tsbuildinfo

# Output of 'npm pack'
*.tgz

# Optional eslint cache
.eslintcache

.lintstagedrc and package.json

In package.json the pre-commit will be initialized with:

1
2
3
4
5
"husky": {
    "hooks": {
        "pre-commit": "lint-staged"
    }
},

In .lintstagedrc will be defined what files to lint before commit:

1
2
3
4
5
6
{
  "src/**/*.ts": "npm run tslint",
  "src/**/*.js": "npm run jslint",
  "src/**/*.vue": "npm run vuelint",
  "src/**/*.css": "npm run csslint"
}

shims-vue.d.ts

To import Vue Components from TypeScript you have to provide type declarations. A generic solution is to declare all Vue files as type Vue:

1
2
3
4
declare module "*.vue" {
  import Vue from "vue";
  export default Vue;
}

Alternatively you could declare any module as any with declare module "*";

.babelrc

This will be used by Babel and the eslint-babel Plugin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
  presets: [
    // This is the all-in-one preset which will manage all needed syntax transforms based
    // on the target browsers configured in ".browserlistrc".
    //
    // To handle polyfills as well we have to set the "useBuiltIns" option. Otherwise an
    // error "regeneratorRuntime is not defined" will be thrown if you use features like
    // "async". This is because the preset will decide to use the plugin
    // "@babel/plugin-transform-regenerator" and the runtime have to be globally accessible.
    // See: [https://github.com/babel/babel/issues/9849#issuecomment-487040428]
    //
    // To make this global accessible you could write in one point of your code (and it have)
    // to be exactly one point) "import 'core-js'; import 'regenerator-runtime/runtime';". A
    // beter solution is to tell babel to handle all these imports. With "useBuiltIns: usage"
    // all the needed import statements will be injected by babel. ANd then Webpack will do
    // the rest. See [https://github.com/babel/babel/issues/9849#issuecomment-646245498]
    //
    // Furthermore we tell babel to use core-js version 3 and use also polyfills for proposals
    // and not just for stable ECMAScript features.
    //
    // A last note: In package.json you will find the depndency to "core-js" which is needed
    // to make everything work. But there is no dependency to "@babel/plugin-transform-regenerator".
    // This is because this plugin is included as dependecy of "@babel/preset-env".
    [ "@babel/preset-env", { "useBuiltIns": "usage", corejs: { version: 3, proposals: true } } ]
  ],
  plugins: [
    // Using experimental feature (stage 3) like public and private field
    //declarations or decorators. We would like to use "loose: true" but there
    //is a problem with inherited static properties. This would not work:
    //  class A {
    //    static p = "A";
    //  }
    //  class B extends A {
    //    static p = "B";
    //  }
    //It leads to an "TypeError" that say that property "p" is read-only.
    ["@babel/proposal-decorators", { "legacy": true }],
    ["@babel/proposal-class-properties", { "loose": false }],
    ["@babel/plugin-proposal-private-methods", { "loose": false }]
    //This one will be added only in production mode
    ["strip-function-call", {strip: "console.debug"}]
  ]
}

.browserlistrc

Many components access this configuration. The included .browserlistrc contains only a very basic configuration:

1
2
3
last 1 version
> 1%
not dead

Just one note: Do not include node targets like maintained node versions because Webpack 5 will throw an error: https://github.com/webpack/webpack/issues/11660

mkdocs.yml

The configuration enables imo the most important features to write a fancy technical documentation using the theme material:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
site_name: CodeCoupler Docs
markdown_extensions:
  - admonition
  - pymdownx.highlight:
      linenums: true
  - pymdownx.superfences
  - def_list
theme:
  name: material
  logo: "logo.png"
  favicon: "logo.png"
  font: false
  features:
    - navigation.instant
    - navigation.tracking
    - navigation.tabs
    - navigation.top
  palette:
    - red: "(prefers-color-scheme: light)"
      scheme: default
      primary: indigo
      accent: indigo
      toggle:
        icon: material/toggle-switch-off-outline
        name: Switch to dark mode
    - media: "(prefers-color-scheme: dark)"
      scheme: slate
      primary: blue
      accent: blue
      toggle:
        icon: material/toggle-switch
        name: Switch to light mode
nav:
  - Home: index.md