diff --git a/CHANGELOG.md b/CHANGELOG.md index f8332f0..6c89d42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # nystudio107/craft Change Log +## 2.2.12 - 2020.07.18 +### Added +* Added TypeScript support +* Use Vue.js 3.0 +* Added `buddy.yml` for atomic deployments + +### Changed +* Replaced moment with vanilla JavaScript +* Replaced `getenv()` with `App::env()` +* No longer use DSN for db connections +* Switch from TSLint to ESLint + +### Fixed +* Fixed config path in the module `helpers/Config.php` + ## 2.2.11 - 2020.05.26 ### Changed * Use DSN for database connections diff --git a/README.md b/README.md index 5499d4c..7b12f11 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ The project is based on [Craft CMS](https://CraftCMS.com) using a unique `templa * [Docker](https://www.docker.com/) Docker is used for local development; see **Setting Up Local Dev** below for details * A base Twig templating setup as described in [An Effective Twig Base Templating Setup](https://nystudio107.com/blog/an-effective-twig-base-templating-setup) * [webpack](https://webpack.js.org/) is used for the build system as per [An Annotated webpack 4 Config for Frontend Web Development](https://nystudio107.com/blog/an-annotated-webpack-4-config-for-frontend-web-development) -* [VueJS](https://vuejs.org/) is used for some of the interactive bits on the website as per +* [TypeScript](https://www.typescriptlang.org/) for strictly typed JavaScript code +* [Vue.js 3.0](https://vuejs.org/) is used for some of the interactive bits on the website, and Vue.js 3.x allows us to leverage the [Composition API](https://composition-api.vuejs.org/) * [Tailwind CSS](https://tailwindcss.com/) for the site-wide CSS * JSON-LD structured data as per [Annotated JSON-LD Structured Data Examples](https://nystudio107.com/blog/annotated-json-ld-structured-data-examples) * [Google AMP](https://developers.google.com/amp/) versions of the podcast episode and other pages @@ -21,7 +22,7 @@ The project is based on [Craft CMS](https://CraftCMS.com) using a unique `templa * A custom site module as per [Enhancing a Craft CMS 3 Website with a Custom Module](https://nystudio107.com/blog/enhancing-a-craft-cms-3-website-with-a-custom-module) * CLI-based queue as per [Robust queue job handling in Craft CMS](https://nystudio107.com/blog/robust-queue-job-handling-in-craft-cms) * FastCGI Static Cache as per [Static Page Caching with Craft CMS](https://nystudio107.com/blog/static-caching-with-craft-cms) -* [Craft-Scripts](https://github.com/nystudio107/craft-scripts) as described in the [Database & Asset Syncing Between Environments in Craft CMS](https://nystudio107.com/blog/database-asset-syncing-between-environments-in-craft-cms), [Mitigating Disaster via Website Backups](https://nystudio107.com/blog/mitigating-disaster-via-website-backups) & [Hardening Craft CMS Permissions](https://nystudio107.com/blog/hardening-craft-cms-permissions) articles +* [buddy.works](http://buddy.works/) atomic deployments ...and probably a bunch of other stuff too. diff --git a/buddy.yml b/buddy.yml new file mode 100644 index 0000000..7956a3e --- /dev/null +++ b/buddy.yml @@ -0,0 +1,134 @@ +- pipeline: "Build & Deploy to Production" + trigger_mode: "ON_EVERY_PUSH" + ref_name: "master" + ref_type: "BRANCH" + target_site_url: "https://CHANGEME.com/" + trigger_condition: "ALWAYS" + actions: + - action: "Execute: webpack build" + type: "BUILD" + working_directory: "/buddy/$PROJECT_SHORTNAME" + docker_image_name: "nystudio107/webpack-dev-base" + docker_image_tag: "latest" + execute_commands: + - "cd docker-config/webpack-dev-craft" + - "npm ci" + - "npm run build" + volume_mappings: + - "/:/buddy/$PROJECT_SHORTNAME" + trigger_condition: "ALWAYS" + shell: "BASH" + - action: "Execute: composer install" + type: "BUILD" + working_directory: "/buddy/$PROJECT_SHORTNAME" + docker_image_name: "nystudio107/php-dev-base" + docker_image_tag: "latest" + execute_commands: + - "cd cms" + - "composer install --no-scripts --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs" + setup_commands: + - "echo \"memory_limit=-1\" >> /usr/local/etc/php/conf.d/buddy.ini" + - "apt-get update && apt-get install -y git zip" + - "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer" + - "# php ext pdo_mysql" + - "docker-php-ext-install pdo_pgsql pgsql" + volume_mappings: + - "/:/buddy/$PROJECT_SHORTNAME" + trigger_condition: "ALWAYS" + shell: "BASH" + - action: "Rsync files to production" + type: "RSYNC" + local_path: "cms/" + remote_path: "$REMOTE_PROJECT_ROOT/deploy-cache" + login: "$REMOTE_SSH_USER" + host: "$REMOTE_SSH_HOST" + port: "22" + authentication_mode: "WORKSPACE_KEY" + archive: true + delete_extra_files: true + recursive: true + compress: true + deployment_excludes: + - "/.git/" + trigger_condition: "ALWAYS" + - action: "Atomic deploy" + type: "SSH_COMMAND" + working_directory: "$REMOTE_PROJECT_ROOT" + login: "$REMOTE_SSH_USER" + host: "$REMOTE_SSH_HOST" + port: "22" + authentication_mode: "WORKSPACE_KEY" + commands: + - "if [ -d \"releases/$BUDDY_EXECUTION_REVISION\" ] && [ \"$BUDDY_EXECUTION_REFRESH\" = \"true\" ];" + - "then" + - " echo \"Removing: releases/$BUDDY_EXECUTION_REVISION\"" + - " rm -rf releases/$BUDDY_EXECUTION_REVISION;" + - "fi" + - "if [ ! -d \"releases/$BUDDY_EXECUTION_REVISION\" ];" + - "then" + - " echo \"Creating: releases/$BUDDY_EXECUTION_REVISION\"" + - " cp -dR deploy-cache releases/$BUDDY_EXECUTION_REVISION;" + - "fi" + - "echo \"Creating: persistent directories\"" + - "mkdir -p storage" + - "echo \"Symlinking: persistent files & directories\"" + - "ln -nfs $REMOTE_PROJECT_ROOT/.env $REMOTE_PROJECT_ROOT/releases/$BUDDY_EXECUTION_REVISION" + - "ln -nfs $REMOTE_PROJECT_ROOT/storage $REMOTE_PROJECT_ROOT/releases/$BUDDY_EXECUTION_REVISION" + - "ln -nfs $REMOTE_PROJECT_ROOT/transcoder $REMOTE_PROJECT_ROOT/releases/$BUDDY_EXECUTION_REVISION/web" + - "echo \"Linking current to revision: $BUDDY_EXECUTION_REVISION\"" + - "rm -f current" + - "ln -s releases/$BUDDY_EXECUTION_REVISION current" + - "echo \"Removing old releases\"" + - "cd releases && ls -t | tail -n +11 | xargs rm -rf" + trigger_condition: "ALWAYS" + run_as_script: true + shell: "BASH" + - action: "Prep Craft CMS" + type: "SSH_COMMAND" + working_directory: "$REMOTE_PROJECT_ROOT/current" + login: "$REMOTE_SSH_USER" + host: "$REMOTE_SSH_HOST" + port: "22" + authentication_mode: "WORKSPACE_KEY" + commands: + - "# Ensure the craft script is executable" + - "chmod a+x craft" + - "# Restart our long running queue listener process" + - "echo \"\" | sudo -S supervisorctl restart all" + - "# Backup the database just in case any migrations or Project Config changes have issues" + - "./craft backup/db" + - "# Run pending migrations, sync project config, and clear caches" + - "./craft migrate/all" + - "./craft project-config/sync" + - "./craft clear-caches/all" + trigger_condition: "ALWAYS" + run_as_script: true + shell: "BASH" + - action: "Send notification to nystudio107 channel" + type: "SLACK" + content: "[#$BUDDY_EXECUTION_ID] $BUDDY_EXECUTION_REVISION_SUBJECT - $BUDDY_EXECUTION_REVISION_COMMITTER_NAME" + blocks: "[{\"type\":\"section\",\"fields\":[{\"type\":\"mrkdwn\",\"text\":\"*Successful execution:* <$BUDDY_EXECUTION_URL|Execution #$BUDDY_EXECUTION_ID $BUDDY_EXECUTION_COMMENT>\"},{\"type\":\"mrkdwn\",\"text\":\"*Pipeline:* <$BUDDY_PIPELINE_URL|$BUDDY_PIPELINE_NAME>\"},{\"type\":\"mrkdwn\",\"text\":\"*Branch:* $BUDDY_EXECUTION_BRANCH\"},{\"type\":\"mrkdwn\",\"text\":\"*Project:* <$BUDDY_PROJECT_URL|$BUDDY_PROJECT_NAME>\"}]}]" + channel: "G6AKRT78V" + channel_name: "nystudio107" + trigger_condition: "ALWAYS" + integration_hash: "5ef0d26820cfeb531cb10738" + - action: "Send notification to nystudio107 channel" + type: "SLACK" + trigger_time: "ON_FAILURE" + content: "[#$BUDDY_EXECUTION_ID] $BUDDY_EXECUTION_REVISION_SUBJECT - $BUDDY_EXECUTION_REVISION_COMMITTER_NAME" + blocks: "[{\"type\":\"section\",\"fields\":[{\"type\":\"mrkdwn\",\"text\":\"*Failed execution:* <$BUDDY_EXECUTION_URL|Execution #$BUDDY_EXECUTION_ID $BUDDY_EXECUTION_COMMENT>\"},{\"type\":\"mrkdwn\",\"text\":\"*Pipeline:* <$BUDDY_PIPELINE_URL|$BUDDY_PIPELINE_NAME>\"},{\"type\":\"mrkdwn\",\"text\":\"*Branch:* $BUDDY_EXECUTION_BRANCH\"},{\"type\":\"mrkdwn\",\"text\":\"*Project:* <$BUDDY_PROJECT_URL|$BUDDY_PROJECT_NAME>\"}]}]" + channel: "G6AKRT78V" + channel_name: "nystudio107" + trigger_condition: "ALWAYS" + integration_hash: "5ef0d26820cfeb531cb10738" + variables: + - key: "PROJECT_SHORTNAME" + value: "CHANGEME" + - key: "PROJECT_URL" + value: "https://CHANGEME.com" + - key: "REMOTE_PROJECT_ROOT" + value: "/home/forge/CHANGEME" + - key: "REMOTE_SSH_HOST" + value: "CHANGEME.com" + - key: "REMOTE_SSH_USER" + value: "forge" diff --git a/cms/config/app.console.php b/cms/config/app.console.php index 9cfa9d4..50a4d87 100644 --- a/cms/config/app.console.php +++ b/cms/config/app.console.php @@ -15,5 +15,7 @@ * This application config is applied only for *only* console requests */ +use craft\helpers\App; + return [ ]; diff --git a/cms/config/app.php b/cms/config/app.php index 9610bce..89d8082 100644 --- a/cms/config/app.php +++ b/cms/config/app.php @@ -17,6 +17,8 @@ * your config/ folder, alongside this one. */ +use craft\helpers\App; + return [ 'modules' => [ 'site-module' => [ diff --git a/cms/config/app.web.php b/cms/config/app.web.php index 9d8ca6e..cf34182 100644 --- a/cms/config/app.web.php +++ b/cms/config/app.web.php @@ -15,6 +15,8 @@ * This application config is applied only for *only* web requests */ +use craft\helpers\App; + return [ 'components' => [ 'session' => [ diff --git a/cms/config/db.php b/cms/config/db.php index 9c584dc..97e931b 100644 --- a/cms/config/db.php +++ b/cms/config/db.php @@ -11,9 +11,12 @@ use craft\helpers\App; return [ - 'dsn' => App::env('DB_DSN'), + 'driver' => App::env('DB_DRIVER'), + 'server' => App::env('DB_SERVER'), 'user' => App::env('DB_USER'), 'password' => App::env('DB_PASSWORD'), + 'database' => App::env('DB_DATABASE'), 'schema' => App::env('DB_SCHEMA'), 'tablePrefix' => App::env('DB_TABLE_PREFIX'), + 'port' => App::env('DB_PORT'), ]; diff --git a/cms/config/fastcgi-cache-bust.php b/cms/config/fastcgi-cache-bust.php index 38e1849..9618c0f 100644 --- a/cms/config/fastcgi-cache-bust.php +++ b/cms/config/fastcgi-cache-bust.php @@ -8,6 +8,8 @@ * @copyright Copyright (c) 2017 nystudio107 */ +use craft\helpers\App; + /** * FastCGI Cache Bust config.php * diff --git a/cms/config/general.php b/cms/config/general.php index 80bf55b..5913bd3 100644 --- a/cms/config/general.php +++ b/cms/config/general.php @@ -8,6 +8,8 @@ * @see \craft\config\GeneralConfig */ +use craft\helpers\App; + return [ // Craft config settings from .env variables 'aliases' => [ diff --git a/cms/config/twigpack.php b/cms/config/twigpack.php index ae1215e..05989c9 100644 --- a/cms/config/twigpack.php +++ b/cms/config/twigpack.php @@ -9,6 +9,8 @@ * @copyright Copyright (c) 2018 nystudio107 */ +use craft\helpers\App; + /** * Twigpack config.php * diff --git a/cms/example.env b/cms/example.env index 75c1693..546c7ac 100644 --- a/cms/example.env +++ b/cms/example.env @@ -10,11 +10,14 @@ RUN_QUEUE_AUTOMATICALLY=1 SECURITY_KEY=EOdiVBONceb8zFGJP7InMui2pMkvNACz # Craft database settings -DB_DSN=mysql:host=mariadb;port=3306;dbname=project +DB_DRIVER=mysql +DB_SERVER=mariadb DB_USER=project DB_PASSWORD=project +DB_DATABASE=project DB_SCHEMA=public DB_TABLE_PREFIX= +DB_PORT= # URL & path settings ASSETS_URL=http://localhost:8000 diff --git a/cms/modules/sitemodule/src/helpers/Config.php b/cms/modules/sitemodule/src/helpers/Config.php index eee5839..caa0ece 100644 --- a/cms/modules/sitemodule/src/helpers/Config.php +++ b/cms/modules/sitemodule/src/helpers/Config.php @@ -43,7 +43,7 @@ public static function getConfigFromFile(string $fileName): array $currentEnv = Craft::$app->getConfig()->env; // Try craft/config first - $path = Craft::getAlias('@craft/config/'.$fileName, false); + $path = Craft::getAlias('@config/'.$fileName, false); if ($path === false || !file_exists($path)) { // Now try our own internal config $path = Craft::getAlias('@modules/sitemodule/'.$fileName, false); diff --git a/composer.json b/composer.json index 44e7578..e7353ba 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "craftcms/craft", "description": "nystudio107 Craft 3.4 CMS scaffolding project", - "version": "2.2.11", + "version": "2.2.12", "keywords": [ "craft", "cms", diff --git a/docker-config/webpack-dev-craft/.eslintignore b/docker-config/webpack-dev-craft/.eslintignore new file mode 100644 index 0000000..e69de29 diff --git a/docker-config/webpack-dev-craft/.eslintrc b/docker-config/webpack-dev-craft/.eslintrc new file mode 100644 index 0000000..94de309 --- /dev/null +++ b/docker-config/webpack-dev-craft/.eslintrc @@ -0,0 +1,17 @@ +{ + "root": true, + "parser": "vue-eslint-parser", + "parserOptions": { + "parser": "@typescript-eslint/parser", + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:vue/vue3-recommended" + ] +} diff --git a/docker-config/webpack-dev-craft/Dockerfile b/docker-config/webpack-dev-craft/Dockerfile index 1f66424..7533725 100755 --- a/docker-config/webpack-dev-craft/Dockerfile +++ b/docker-config/webpack-dev-craft/Dockerfile @@ -2,6 +2,8 @@ FROM nystudio107/webpack-dev-base WORKDIR /var/www/project/docker-config/webpack-dev-craft/ +COPY ./docker-config/webpack-dev-craft/tsconfig.json /var/www/project/tsconfig.json + # Run our webpack build in debug mode # We'd normally use `npm ci` here, but by using `install`: diff --git a/docker-config/webpack-dev-craft/package.json b/docker-config/webpack-dev-craft/package.json index ba6c3f7..3d3b098 100644 --- a/docker-config/webpack-dev-craft/package.json +++ b/docker-config/webpack-dev-craft/package.json @@ -24,6 +24,8 @@ }, "private": true, "scripts": { + "check-types": "tsc", + "lint": "tsc --noEmit && eslint '../../src/**/*.{js,ts,vue}' --fix", "debug": "webpack-dev-server --config webpack.dev.js", "dev": "webpack-dashboard -- webpack-dev-server --config webpack.dev.js", "build": "webpack --config webpack.prod.js --progress --hide-modules" @@ -54,12 +56,22 @@ }, "devDependencies": { "@babel/core": "^7.1.0", + "@babel/plugin-proposal-class-properties": "7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1", + "@babel/plugin-proposal-object-rest-spread": "7.9.0", + "@babel/plugin-proposal-optional-chaining": "^7.10.1", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-transform-runtime": "^7.1.0", "@babel/preset-env": "^7.1.0", "@babel/register": "^7.0.0", "@babel/runtime": "^7.0.0", + "@babel/preset-typescript": "^7.9.0", "@gfx/zopfli": "^1.0.11", + "@types/node": "^14.0.13", + "@types/webpack-env": "^1.15.2", + "@typescript-eslint/eslint-plugin": "^3.6.1", + "@typescript-eslint/parser": "^3.6.1", + "@vue/compiler-sfc": "^3.0.0-beta.2", "babel-loader": "^8.0.2", "clean-webpack-plugin": "^3.0.0", "compression-webpack-plugin": "^2.0.0", @@ -67,10 +79,14 @@ "create-symlink-webpack-plugin": "^1.0.0", "critical": "^1.3.4", "critical-css-webpack-plugin": "^0.2.0", - "css-loader": "^2.1.0", + "css-loader": "^3.4.2", "cssnano": "^4.1.0", "dotenv": "^6.1.0", - "file-loader": "^2.0.0", + "eslint": "^7.4.0", + "eslint-plugin-vue": "^7.0.0-alpha.10", + "file-loader": "^6.0.0", + "fork-ts-checker-notifier-webpack-plugin": "^3.0.0", + "fork-ts-checker-webpack-plugin": "^5.0.1", "git-rev-sync": "^1.12.0", "glob-all": "^3.1.0", "html-webpack-plugin": "^3.2.0", @@ -83,7 +99,7 @@ "imagemin-webp": "^5.0.0", "imagemin-webp-webpack-plugin": "^3.1.0", "img-loader": "^3.0.1", - "mini-css-extract-plugin": "^0.4.3", + "mini-css-extract-plugin": "^0.9.0", "optimize-css-assets-webpack-plugin": "^5.0.1", "postcss": "^7.0.2", "postcss-import": "^12.0.0", @@ -98,9 +114,12 @@ "style-loader": "^0.23.0", "symlink-webpack-plugin": "^0.0.4", "terser-webpack-plugin": "^1.1.0", - "vue-loader": "^15.4.2", + "ts-loader": "^7.0.1", + "tsconfig-paths-webpack-plugin": "^3.2.0", + "typescript": "^3.8.3", + "typings-for-css-modules-loader": "^1.7.0", + "vue-loader": "^16.0.0-alpha.3", "vue-style-loader": "^4.1.2", - "vue-template-compiler": "^2.5.17", "webapp-webpack-plugin": "https://github.com/brunocodutra/webapp-webpack-plugin.git", "webpack": "^4.19.1", "webpack-bundle-analyzer": "^3.0.2", @@ -117,7 +136,7 @@ "core-js": "^3.0.0", "regenerator-runtime": "^0.13.2", "tailwindcss": "^1.0.0", - "vue": "^2.5.17", - "vue-confetti": "^0.4.2" + "vue": "^3.0.0-beta.14", + "vue-confetti": "^2.0.8" } } diff --git a/docker-config/webpack-dev-craft/tsconfig.json b/docker-config/webpack-dev-craft/tsconfig.json new file mode 100644 index 0000000..e21596c --- /dev/null +++ b/docker-config/webpack-dev-craft/tsconfig.json @@ -0,0 +1,39 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "baseUrl": "docker-config/webpack-dev-craft/node_modules", + "declaration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "importHelpers": true, + "module": "esnext", + "moduleResolution": "node", + "noEmit": true, + "noImplicitAny": true, + "outDir": "./cms/web/dist/", + "paths": { + "@/*": [ + "./src/*" + ] + }, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "strictBindCallApply": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "target": "esnext", + "typeRoots": [ + "docker-config/webpack-dev-craft/node_modules/@types" + ] + }, + "include": [ + "./src/**/*.ts", + "./src/**/*.vue" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/docker-config/webpack-dev-craft/webpack.common.js b/docker-config/webpack-dev-craft/webpack.common.js index daba157..f97b71e 100644 --- a/docker-config/webpack-dev-craft/webpack.common.js +++ b/docker-config/webpack-dev-craft/webpack.common.js @@ -8,8 +8,10 @@ const merge = require('webpack-merge'); // webpack plugins const CopyWebpackPlugin = require('copy-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); -const VueLoaderPlugin = require('vue-loader/lib/plugin'); +const { VueLoaderPlugin } = require('vue-loader'); const WebpackNotifierPlugin = require('webpack-notifier'); // config files @@ -29,28 +31,54 @@ const configureBabelLoader = (browserList, legacy) => { presets: [ [ '@babel/preset-env', { - modules: legacy ? "auto" : false, - corejs: { - version: 3, - proposals: true - }, - debug: false, - useBuiltIns: 'usage', - targets: { - browsers: browserList, - }, - } + modules: legacy ? "auto" : false, + corejs: { + version: 3, + proposals: true + }, + debug: false, + useBuiltIns: 'usage', + targets: { + browsers: browserList, + }, + } + ], + [ + '@babel/preset-typescript', { + 'allExtensions': true, + 'isTSX': false, + } ], ], plugins: [ '@babel/plugin-syntax-dynamic-import', '@babel/plugin-transform-runtime', + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-proposal-nullish-coalescing-operator', + '@babel/plugin-proposal-optional-chaining', ], }, }, }; }; +// Configure TypeScript loader +const configureTypeScriptLoader = () => { + return { + test: /\.ts$/, + exclude: settings.typescriptLoaderConfig.exclude, + use: { + loader: 'ts-loader', + options: { + transpileOnly: true, + appendTsSuffixTo: [/\.vue$/], + happyPackMode: false, + }, + }, + }; +}; + // Configure Entries const configureEntries = () => { let entries = {}; @@ -105,8 +133,9 @@ const baseConfig = { publicPath: settings.urls.publicPath() }, resolve: { + extensions: ['.ts', '.js', '.vue', '.json'], alias: { - 'vue$': 'vue/dist/vue.esm.js' + 'vue$': 'vue/dist/vue.esm-bundler.js' }, modules: [ path.resolve(__dirname, 'node_modules'), @@ -121,6 +150,19 @@ const baseConfig = { plugins: [ new WebpackNotifierPlugin({title: 'Webpack', excludeWarnings: true, alwaysNotify: true}), new VueLoaderPlugin(), + new ForkTsCheckerWebpackPlugin({ + typescript: { + configFile: '../../tsconfig.json', + extensions: { + vue: true + } + } + }), + new ForkTsCheckerNotifierWebpackPlugin({ + title: 'Webpack', + excludeWarnings: true, + alwaysNotify: false, + }), ] }; @@ -129,6 +171,7 @@ const legacyConfig = { module: { rules: [ configureBabelLoader(Object.values(pkg.browserslist.legacyBrowsers, true)), + configureTypeScriptLoader(), ], }, plugins: [ @@ -146,6 +189,7 @@ const modernConfig = { module: { rules: [ configureBabelLoader(Object.values(pkg.browserslist.modernBrowsers, false)), + configureTypeScriptLoader(), ], }, plugins: [ diff --git a/docker-config/webpack-dev-craft/webpack.settings.js b/docker-config/webpack-dev-craft/webpack.settings.js index 24244b2..a2cc95b 100644 --- a/docker-config/webpack-dev-craft/webpack.settings.js +++ b/docker-config/webpack-dev-craft/webpack.settings.js @@ -32,7 +32,7 @@ module.exports = { cssName: "styles" }, entries: { - "app": "app.js", + "app": "app.ts", }, babelLoaderConfig: { exclude: [ @@ -119,6 +119,11 @@ module.exports = { symlink: "../favicon.ico" } ], + typescriptLoaderConfig: { + exclude: [ + /(node_modules)/ + ], + }, webappConfig: { logo: "../../src/img/favicon-src.png", prefix: "img/favicons/" diff --git a/src/js/@types/shims.d.ts b/src/js/@types/shims.d.ts new file mode 100644 index 0000000..8bfbcc6 --- /dev/null +++ b/src/js/@types/shims.d.ts @@ -0,0 +1 @@ +declare module "app"; diff --git a/src/js/app.js b/src/js/app.js deleted file mode 100644 index 69573bd..0000000 --- a/src/js/app.js +++ /dev/null @@ -1,32 +0,0 @@ -// Import our CSS -import styles from '../css/app.pcss'; - -// App main -const main = async () => { - // Async load the vue module - const { default: Vue } = await import(/* webpackChunkName: "vue" */ 'vue'); - // Create our vue instance - const vm = new Vue({ - el: "#page-container", - components: { - 'confetti': () => import(/* webpackChunkName: "confetti" */ '../vue/Confetti.vue'), - }, - data: { - }, - methods: { - }, - mounted() { - }, - }); - - return vm; -}; - -// Execute async function -main().then( (vm) => { -}); - -// Accept HMR as per: https://webpack.js.org/api/hot-module-replacement#accept -if (module.hot) { - module.hot.accept(); -} diff --git a/src/js/app.ts b/src/js/app.ts new file mode 100644 index 0000000..7374e28 --- /dev/null +++ b/src/js/app.ts @@ -0,0 +1,34 @@ +// Import our CSS +import '../css/app.pcss'; + +// App main +const main = async () => { + // Async load the Vue 3 APIs we need from the Vue ESM + const { createApp, defineAsyncComponent } = await import(/* webpackChunkName: "vue" */ 'vue'); + // Create our vue instance + const app = createApp({ + components: { + 'confetti': defineAsyncComponent(() => import(/* webpackChunkName: "confetti" */ '../vue/Confetti.vue')), + }, + data: () => ({ + }), + methods: { + }, + mounted() { + }, + }); + + // Mount the app + const root = app.mount("#page-container"); + + return root; +}; + +// Execute async function +main().then( (root) => { +}); + +// Accept HMR as per: https://webpack.js.org/api/hot-module-replacement#accept +if (module.hot) { + module.hot.accept(); +} diff --git a/src/vue/@types/confetti.d.ts b/src/vue/@types/confetti.d.ts new file mode 100644 index 0000000..a1dce00 --- /dev/null +++ b/src/vue/@types/confetti.d.ts @@ -0,0 +1,19 @@ +declare module "vue-confetti/src/confetti.js"; + +interface ParticlesConfig { + type : string, + size : number, + dropRate : number, + colors : string[], + url : string | null, +} + +interface ConfettiConfig { + particles : Partial[], + defaultType : string, + defaultSize : number, + defaultDropRate : number, + defaultColors : string[], + canvasId : number, + particlesPerFrame : number, +} diff --git a/src/vue/@types/shims-vue.d.ts b/src/vue/@types/shims-vue.d.ts new file mode 100644 index 0000000..7c65cb3 --- /dev/null +++ b/src/vue/@types/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import { defineComponent } from "vue"; + const Component : ReturnType; + export default Component; +} diff --git a/src/vue/Confetti.vue b/src/vue/Confetti.vue index 4a00f2c..6bebc18 100644 --- a/src/vue/Confetti.vue +++ b/src/vue/Confetti.vue @@ -1,24 +1,29 @@ - diff --git a/tsconfig.json b/tsconfig.json new file mode 120000 index 0000000..c5d0b47 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1 @@ +docker-config/webpack-dev-craft/tsconfig.json \ No newline at end of file