├── .babelrc
├── .postcssrc
├── src
├── assets
│ └── scss
│ │ ├── settings
│ │ └── _spacings.scss
│ │ └── generic
│ │ └── _base.scss
├── main.js
├── utils
│ └── external-component.js
└── App.vue
├── server
├── components
│ └── MyComponent
│ │ └── MyComponent.vue
└── index.js
├── public
├── favicon.ico
└── index.html
├── .editorconfig
├── vue.config.js
├── .gitignore
├── .eslintrc.js
├── README.md
└── package.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@vue/app"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.postcssrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": {
3 | "autoprefixer": {}
4 | }
5 | }
--------------------------------------------------------------------------------
/src/assets/scss/settings/_spacings.scss:
--------------------------------------------------------------------------------
1 | @import '~@avalanche/setting-spacings';
2 |
--------------------------------------------------------------------------------
/server/components/MyComponent/MyComponent.vue:
--------------------------------------------------------------------------------
1 |
2 | Hello from the Distribution Server!
3 |
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maoberlehner/distributed-vue-applications-loading-components-via-http/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import App from './App.vue';
4 |
5 | Vue.config.productionTip = false;
6 |
7 | new Vue({
8 | render: h => h(App),
9 | }).$mount(`#app`);
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_size = 2
9 | indent_style = space
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const nodeSassMagicImporter = require(`node-sass-magic-importer`);
2 |
3 | module.exports = {
4 | css: {
5 | loaderOptions: {
6 | sass: {
7 | importer: nodeSassMagicImporter(),
8 | },
9 | },
10 | },
11 | lintOnSave: false,
12 | };
13 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const express = require(`express`);
2 | const path = require(`path`);
3 |
4 | const PORT = 8200;
5 |
6 | const app = express();
7 |
8 | app.use(express.static(path.resolve(__dirname, `components`), {
9 | maxAge: `365d`,
10 | }));
11 |
12 | app.listen(PORT);
13 |
14 | // eslint-disable-next-line no-console
15 | console.log(`Listening on: http://localhost:${PORT}`);
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Numerous always-ignore extensions
2 | *.diff
3 | *.err
4 | *.log
5 | *.orig
6 | *.rej
7 | *.swo
8 | *.swp
9 | *.tgz
10 | *.vi
11 | *.zip
12 | *~
13 |
14 | # OS or Editor folders
15 | ._*
16 | .cache
17 | .DS_Store
18 | .idea
19 | .project
20 | .settings
21 | .tmproj
22 | *.esproj
23 | *.sublime-project
24 | *.sublime-workspace
25 | nbproject
26 | Thumbs.db
27 |
28 | # Folders to ignore
29 | dist/*
30 | node_modules
31 |
32 | # Files to ignore
33 | *.map
34 | *.min.js
35 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Distributed Vue.js Applications Part 1: Loading Components via HTTP
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/utils/external-component.js:
--------------------------------------------------------------------------------
1 | export default async function externalComponent(url) {
2 | const name = url.split(`/`).reverse()[0].match(/^(.*?)\.umd/)[1];
3 |
4 | if (window[name]) return window[name];
5 |
6 | window[name] = new Promise((resolve, reject) => {
7 | const script = document.createElement(`script`);
8 | script.async = true;
9 | script.addEventListener(`load`, () => {
10 | resolve(window[name]);
11 | });
12 | script.addEventListener(`error`, () => {
13 | reject(new Error(`Error loading ${url}`));
14 | });
15 | script.src = url;
16 | document.head.appendChild(script);
17 | });
18 |
19 | return window[name];
20 | }
21 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: [
4 | `plugin:vue/recommended`,
5 | `@avalanche/eslint-config`,
6 | ],
7 | rules: {
8 | 'no-console': process.env.NODE_ENV === `production` ? `error` : `warn`,
9 | 'no-debugger': process.env.NODE_ENV === `production` ? `error` : `warn`,
10 | 'vue/component-name-in-template-casing': [`error`,
11 | `PascalCase`,
12 | ],
13 | 'vue/no-v-html': false,
14 | 'vue/html-closing-bracket-spacing': [`error`, {
15 | startTag: `never`,
16 | endTag: `never`,
17 | selfClosingTag: `never`,
18 | }],
19 | },
20 | parserOptions: {
21 | parser: `babel-eslint`,
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Distributed Vue.js Applications Part 1: Loading Components via HTTP
2 |
3 | [](https://www.patreon.com/maoberlehner)
4 | [](https://paypal.me/maoberlehner)
5 |
6 | This is an example project for the following article: [Distributed Vue.js Applications Part 1: Loading Components via HTTP](https://markus.oberlehner.net/blog/distributed-vue-applications-loading-components-via-http/)
7 |
8 | ## Build Setup
9 |
10 | ```bash
11 | # Install dependencies.
12 | npm install
13 |
14 | # Start the distribution server.
15 | node server/index.js
16 |
17 | # Serve the client application with hot reload.
18 | npm run serve
19 |
20 | # Build the client application for production with minification.
21 | npm run build
22 | ```
23 |
24 | ## About
25 |
26 | ### Author
27 |
28 | Markus Oberlehner
29 | Website: https://markus.oberlehner.net
30 | Twitter: https://twitter.com/MaOberlehner
31 | PayPal.me: https://paypal.me/maoberlehner
32 | Patreon: https://www.patreon.com/maoberlehner
33 |
34 | ### License
35 |
36 | MIT
37 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
Distributed Vue.js Applications Part 1: Loading Components via HTTP
7 |
8 |
9 |
10 |
11 |
23 |
24 |
35 |
36 |
48 |
--------------------------------------------------------------------------------
/src/assets/scss/generic/_base.scss:
--------------------------------------------------------------------------------
1 | @import '~@avalanche/generic-box-sizing-reset';
2 | @import '~reset-css/sass/reset';
3 |
4 | // 1. Usually a larger line height is beneficial
5 | // for blocks of text, but we want to have a
6 | // rather small line height for our basic UI
7 | // elements so we can apply uniform spacings
8 | // using margins and paddings. We'll add an
9 | // extra CSS class with a larger line height
10 | // to apply to blocks of text.
11 | // 2. A kind of “dirty” white is more pleasing
12 | // to the eyes.
13 | // 3. A kind of “almost black but not quite black”
14 | // is also more pleasing to the eyes.
15 | body {
16 | line-height: 1.25; // 1
17 | background-color: #f9f9f9; // 2
18 | color: #222; // 3
19 | font-family: sans-serif;
20 | }
21 |
22 | // 1. Larger font sizes need less line height.
23 | h1,
24 | h2,
25 | h3,
26 | h4,
27 | h5 {
28 | line-height: 1.2; // 1
29 | font-weight: 700;
30 | }
31 |
32 | h1 {
33 | font-size: 2.027em;
34 | }
35 |
36 | h2 {
37 | font-size: 1.802em;
38 | }
39 |
40 | h3 {
41 | font-size: 1.602em;
42 | }
43 |
44 | h4 {
45 | font-size: 1.424em;
46 | }
47 |
48 | h5 {
49 | font-size: 1.266em;
50 | }
51 |
52 | h6 {
53 | font-size: 1.125em;
54 | }
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "distributed-vue-applications-loading-components-via-http",
3 | "version": "0.1.0",
4 | "author": "Markus Oberlehner",
5 | "homepage": "https://github.com/maoberlehner/distributed-vue-applications-loading-components-via-http",
6 | "license": "MIT",
7 | "private": true,
8 | "scripts": {
9 | "serve": "vue-cli-service serve",
10 | "build": "vue-cli-service build",
11 | "lint": "vue-cli-service lint"
12 | },
13 | "dependencies": {
14 | "@avalanche/generic-box-sizing-reset": "^4.0.0-alpha.5",
15 | "@avalanche/object-container": "^4.0.0-alpha.8",
16 | "@avalanche/object-vertical-spacing": "^4.0.0-alpha.5",
17 | "@avalanche/setting-spacings": "^4.0.0-alpha.6",
18 | "@vue/cli-plugin-babel": "^3.5.5",
19 | "@vue/cli-service": "^3.5.3",
20 | "express": "^4.16.4",
21 | "node-sass": "^4.11.0",
22 | "node-sass-magic-importer": "^5.3.1",
23 | "reset-css": "^4.0.1",
24 | "sass-loader": "^7.1.0",
25 | "vue": "^2.6.10",
26 | "vue-template-compiler": "^2.6.10"
27 | },
28 | "devDependencies": {
29 | "@avalanche/eslint-config": "^3.0.0",
30 | "@vue/cli-plugin-eslint": "^3.5.1",
31 | "eslint-plugin-import": "^2.16.0",
32 | "eslint-plugin-vue": "^5.2.2"
33 | },
34 | "browserslist": [
35 | ">0.25%",
36 | "not ie 10",
37 | "not op_mini all"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------