Skip to content

CodeCoupler Webpack Development Details: Boilerplate Files

All the files of the boilerplate explained:

.vscode/settings.json

{

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

  //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": "explicit",
    "source.fixAll.stylelint": "explicit",
    "source.fixAll.markdownlint": "explicit"
  },

  //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"

  //Removed support of Vetur in Boilerplate Version 2.2
  //"vetur.validation.template": false,

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

  //Show all three breakpoints that will be uitilized by the boilerplates
  "editor.rulers": [80, 100, 120]

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

{

  // 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": {
    // Add Prettier Ruls and use the file ".prettierc". With this the rules which will use
    // ESLint are in sync with the rules that will be used by Prettier. After changing the
    // ".prettierrc" file the ESLint server must be restartet!
    "prettier/prettier": [
      "error",
      {},
      {
        "usePrettierrc": true
      }
    ]
  },

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

For HTML we like to have more space.

{
  "printWidth": 80,
  "trailingComma": "none",
  "overrides": [
    {
      "files": "*.md",
      "options": {
        "printWidth": 100,
        "proseWrap": "always"
      }
    },
    {
      "files": ["*.html", "*.vue"],
      "options": {
        "printWidth": 120
      }
    }
  ]
}

.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

{
  "plugins": {
    // Compile modern (and experimental) CSS for targeted browsers
    "postcss-preset-env": {
      stage: 0
    },

    // Removed in 4.1:
    //
    // "postcss-import": {},
    //
    // 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.
    //
    // But this was removed because this did not work if the @import
    // rule tries to import a scss syntax. Like in Bootstrap where
    // you have to import all stylesheets with 
    //
    //    @import "bootstrap/scss/bootstrap";

    // Removed in 4.1:
    //
    // "autoprefixer": {},
    //
    // The plugin is already included in "postcss-preset-env"

    // Removed in 4.1:
    //
    // "cssnano": {}
    //
    // From version 3.13 the "css-minimizer-webpack-plugin"
    // will be used for mangling and minifying CSS.

  }
}

.stylelintrc

{
  // Moved from ".stylelintignore" because this will not work in monorepos
  // with nested packages (https://github.com/stylelint/vscode-stylelint/issues/155).
  "ignoreFiles": ["dist/**", "node_modules/**"],
  // 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,
    // This addition make using CSS Module Pseudo Classes usable
    "selector-pseudo-class-no-unknown": [
      true,
      {
        "ignorePseudoClasses": [
          "local",
          "global"
        ]
      }
    ]
  }
}

tsconfig.json

{
  "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,
    //Support for Volar Plugin. Without this setting the plugin complain
    //the tag <script> in vue files because of missing the attribute lang="ts"
    "allowJs": 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

# 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

husky setup: hook files, .lintstagedrc and package.json

In package.json thusky will be initialized everytime npm i is executed:

1
2
3
4
5
{
  "scripts": {
      "prepare": "husky"
  }
}

In the driectory .husky the prepare commit script is defined in the pre-commit file:

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

{
  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