├── .gitignore
├── README.md
├── docker-compose.yml
├── nginx.conf
├── pure-web-component-chart-app
├── package.json
├── src
│ ├── assets
│ │ ├── img
│ │ │ └── 290408.png
│ │ └── js
│ │ │ └── com.bundle.js
│ ├── components
│ │ └── chart-container.js
│ ├── index.html
│ └── index.js
└── webpack.config.js
├── pure-web-component-main-app
├── package.json
├── src
│ ├── assets
│ │ └── js
│ │ │ ├── chart.bundle.js
│ │ │ └── menu.bundle.js
│ ├── components
│ │ └── main-layout.js
│ ├── index.html
│ └── index.js
└── webpack.config.js
└── pure-web-component-menu-app
├── package.json
├── src
├── assets
│ └── img
│ │ └── 290408.png
├── components
│ └── left-menu.js
├── index.html
└── index.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | pure-web-component-chart-app/node_modules/
2 | pure-web-component-main-app/node_modules/
3 | pure-web-component-menu-app/dist/
4 | pure-web-component-menu-app/node_modules/
5 | */.idea/*
6 | pure-web-component-chart-app/dist/
7 | package-lock.json
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is the demo project to prove the potential of micro frontend architecture.
2 |
3 | # Build the micro apps
4 |
5 | Go to pure-web-component-menu-app and run
6 |
7 | ```sh
8 | npm install
9 | ```
10 | After successfully installing dependencies we build the project
11 | ```sh
12 | npm run build
13 | ```
14 |
15 | Repeat above steps with pure-web-component-chart-app and pure-web-component-main-app
16 |
17 |
18 |
19 | # Run app
20 |
21 | We simulate the way of micro frontends works, so we need Docker to create many nodes of FE. The Docker installed in your pc is required.
22 |
23 | Create a docker network by running the command:
24 |
25 | Mac OS
26 | ```sh
27 | docker network create nginx_network
28 | ```
29 | Windows
30 | ```sh
31 | docker network create --driver nat nginx_network
32 | ```
33 |
34 | Start the docker containers by run
35 |
36 | ```sh
37 | docker-compose up
38 | ```
39 |
40 | Launch the browser navigate to [Localhost](http://localhost:8000/)
41 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | nginx:
4 | image: nginx
5 | volumes:
6 | - ./nginx.conf:/etc/nginx/conf.d/default.conf
7 | - ./pure-web-component-main-app/dist/:/home/main/
8 | - ./pure-web-component-menu-app/dist/:/home/left-side/
9 | - ./pure-web-component-chart-app/dist/:/home/right-side/
10 | ports:
11 | - 8000:8000
12 | - 2000:2000
13 | - 3000:3000
14 | networks:
15 | - nginx_network
16 | networks:
17 | nginx_network:
18 | external: true
19 |
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | server {
3 | server_name gateway;
4 | listen 8000;
5 |
6 | location /left {
7 | proxy_pass http://localhost:2000;
8 | }
9 |
10 | location /right {
11 | proxy_pass http://localhost:3000;
12 | }
13 |
14 | location / {
15 | root /home/main/;
16 | }
17 | }
18 |
19 | server {
20 | server_name left;
21 | listen 2000;
22 |
23 | location / {
24 | root /home/left-side/;
25 | }
26 | }
27 | server {
28 | server_name right;
29 | listen 3000;
30 |
31 | location / {
32 | root /home/right-side/;
33 | }
34 | }
--------------------------------------------------------------------------------
/pure-web-component-chart-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pure-web-component-main-app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --mode production",
8 | "watch": "webpack --watch",
9 | "start": "webpack-dev-server --open"
10 | },
11 | "devDependencies": {
12 | "@webcomponents/webcomponentsjs": "^2.4.4",
13 | "clean-webpack-plugin": "^3.0.0",
14 | "copy-webpack-plugin": "^6.0.3",
15 | "css-loader": "^4.2.2",
16 | "file-loader": "^6.0.0",
17 | "html-webpack-plugin": "^4.3.0",
18 | "sass-loader": "^10.0.1",
19 | "style-loader": "^1.2.1",
20 | "url-loader": "^4.1.0",
21 | "webpack": "^4.44.1",
22 | "webpack-cli": "^3.3.12",
23 | "webpack-dev-server": "^3.11.0"
24 | },
25 | "author": "",
26 | "license": "ISC",
27 | "dependencies": {
28 | "chart.js": "^2.9.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pure-web-component-chart-app/src/assets/img/290408.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vo-shared/microfrontend-pure-webcomponent/8f2ec837ebb03404e203f751c4d5cf29f681afdf/pure-web-component-chart-app/src/assets/img/290408.png
--------------------------------------------------------------------------------
/pure-web-component-chart-app/src/assets/js/com.bundle.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);class r extends HTMLElement{connectedCallback(){const e=document.createElement("div");this.attachShadow({mode:"open"}).appendChild(e)}}customElements.define("r-left-menu",r);class o extends HTMLElement{connectedCallback(){this.innerHTML='
'}}customElements.define("r-widget-frame",o);class c extends HTMLElement{connectedCallback(){this.innerHTML='
\n This is chart\n
'}}customElements.define("r-main-layout",c)}]);
--------------------------------------------------------------------------------
/pure-web-component-chart-app/src/components/chart-container.js:
--------------------------------------------------------------------------------
1 | import Chart from 'chart.js';
2 | export class ChartContainer extends HTMLElement {
3 |
4 | get type() {
5 | return this.getAttribute('type');
6 | }
7 | set type(newVal) {
8 | this.setAttribute('type', newVal);
9 | }
10 |
11 |
12 | constructor() {
13 | super();
14 | this.innerHTML = this.renderPage();
15 | this.initChart();
16 | }
17 |
18 | renderPage() {
19 | return `
20 |
21 |
22 |
`;
23 | }
24 | initChart(){
25 | const chartType = this.type;
26 | const ctx = document.getElementById('myChart');
27 | const myChart = new Chart(ctx, {
28 | type: chartType,
29 | data: {
30 | labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
31 | datasets: [{
32 | label: '# of Votes',
33 | data: [12, 19, 3, 5, 2, 3],
34 | backgroundColor: [
35 | 'rgba(255, 99, 132, 0.2)',
36 | 'rgba(54, 162, 235, 0.2)',
37 | 'rgba(255, 206, 86, 0.2)',
38 | 'rgba(75, 192, 192, 0.2)',
39 | 'rgba(153, 102, 255, 0.2)',
40 | 'rgba(255, 159, 64, 0.2)'
41 | ],
42 | borderColor: [
43 | 'rgba(255, 99, 132, 1)',
44 | 'rgba(54, 162, 235, 1)',
45 | 'rgba(255, 206, 86, 1)',
46 | 'rgba(75, 192, 192, 1)',
47 | 'rgba(153, 102, 255, 1)',
48 | 'rgba(255, 159, 64, 1)'
49 | ],
50 | borderWidth: 1
51 | }]
52 | },
53 | options: {
54 | scales: {
55 | yAxes: [{
56 | ticks: {
57 | beginAtZero: true
58 | }
59 | }]
60 | }
61 | }
62 | });
63 | }
64 |
65 | }
66 | customElements.define('chart-container', ChartContainer);
67 |
--------------------------------------------------------------------------------
/pure-web-component-chart-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Example of Webcomponent
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/pure-web-component-chart-app/src/index.js:
--------------------------------------------------------------------------------
1 | import './components/chart-container';
--------------------------------------------------------------------------------
/pure-web-component-chart-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const {CleanWebpackPlugin} = require('clean-webpack-plugin');
4 | const CopyWebpackPlugin = require('copy-webpack-plugin');
5 |
6 | module.exports = (env, argv)=>({
7 | mode: 'development',
8 | entry: {
9 | app: './src/index.js'
10 | },
11 | devServer: {
12 | contentBase: path.join(__dirname, 'dist'),
13 | historyApiFallback: true
14 | },
15 | devtool: argv.mode === 'production'? 'none' : 'inline-source-map',
16 | externals: {
17 | 'react': {commonjs: 'react'},
18 | 'react-dom': {commonjs: 'react-dom'}
19 | },
20 | plugins: [
21 | new CleanWebpackPlugin(),
22 | new HtmlWebpackPlugin({
23 | template: './src/index.html'
24 | }),
25 | new CopyWebpackPlugin({
26 | patterns: [
27 | {
28 | context: 'node_modules/@webcomponents/webcomponentsjs',
29 | from: '**/*.js',
30 | to: 'webcomponents'
31 | },
32 | {
33 | from: './src/assets/img/*',
34 | to: './',
35 | flatten: true
36 | }
37 | ]
38 | })
39 | ],
40 | output: {
41 | filename: 'chart.bundle.js',
42 | path: path.resolve(__dirname, 'dist')
43 | },
44 | module: {
45 | rules: [
46 | {
47 | test: /\.tsx?$/,
48 | use: 'ts-loader',
49 | exclude: /node_modules/
50 | },
51 | {
52 | test: /\.css$/,
53 | include: path.resolve(__dirname, 'src'),
54 | use: [
55 | 'style-loader',
56 | 'css-loader'
57 | ]
58 | },
59 | {test: /\.s[a|c]ss$/, use: [{loader: "style-loader"}, {loader: "css-loader"}, {loader: "sass-loader"}]},
60 | {test: /\.(png|gif|jpg|cur)$/i, loader: 'url-loader', options: {limit: 8192}},
61 | {
62 | test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
63 | loader: 'url-loader',
64 | options: {limit: 10000, mimetype: 'application/font-woff2'}
65 | },
66 | {
67 | test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
68 | loader: 'url-loader',
69 | options: {limit: 10000, mimetype: 'application/font-woff'}
70 | },
71 | {test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'file-loader'}
72 | ]
73 | },
74 | resolve: {
75 | extensions: ['.js', 'jsx']
76 | }
77 | });
--------------------------------------------------------------------------------
/pure-web-component-main-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pure-web-component-main-app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --mode production",
8 | "watch": "webpack --watch",
9 | "start": "webpack-dev-server --open"
10 | },
11 | "devDependencies": {
12 | "@webcomponents/webcomponentsjs": "^2.4.4",
13 | "clean-webpack-plugin": "^3.0.0",
14 | "copy-webpack-plugin": "^6.0.3",
15 | "css-loader": "^4.2.2",
16 | "file-loader": "^6.0.0",
17 | "html-webpack-plugin": "^4.3.0",
18 | "sass-loader": "^10.0.1",
19 | "style-loader": "^1.2.1",
20 | "url-loader": "^4.1.0",
21 | "webpack": "^4.44.1",
22 | "webpack-cli": "^3.3.12",
23 | "webpack-dev-server": "^3.11.0"
24 | },
25 | "author": "",
26 | "license": "ISC",
27 | "dependencies": {
28 | "@google-web-components/google-chart": "^4.0.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pure-web-component-main-app/src/assets/js/menu.bundle.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function n(i){if(t[i])return t[i].exports;var r=t[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(i,r,function(t){return e[t]}.bind(null,r));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);class i extends HTMLElement{get items(){return JSON.parse(this.getAttribute("items"))}set items(e){this.setAttribute("items",JSON.stringify(e))}get active(){return this.getAttribute("active")}set active(e){this.setAttribute("active",e)}get template(){const e=document.createElement("template");return e.innerHTML='
\n
',e}constructor(){super(),this.attachShadow({mode:"open"}),this.items=[{id:"bar",name:"Bar chart"},{id:"line",name:"Line chart"},{id:"radar",name:"Radar chart"},{id:"bubble",name:"Bubble chart"},{id:"pie",name:"Pie chart"}],this.shadowRoot.appendChild(this.template.content.cloneNode(!0)),this.renderChildren()}renderChildren(){const e=this.shadowRoot.querySelector("#menu-list");this.items&&this.items.length>0&&this.items.forEach(t=>{const n=document.createElement("li");n.className="list-group-item"+(this.active===t.id?" active":""),n.innerText=t.name,n.key=t.id,n.addEventListener("click",e=>{this.dispatchEvent(new CustomEvent("my-event",{bubbles:!0,detail:{menuId:n.key}}))}),e.appendChild(n)})}}customElements.define("left-menu",i)}]);
--------------------------------------------------------------------------------
/pure-web-component-main-app/src/components/main-layout.js:
--------------------------------------------------------------------------------
1 |
2 | export class MainLayout extends HTMLElement {
3 |
4 | get active() {
5 | return this.getAttribute('active');
6 | }
7 | set active(newVal) {
8 | this.setAttribute('active', newVal);
9 | }
10 |
11 | static get observedAttributes() {
12 | return ['active'];
13 | }
14 | constructor() {
15 | super();
16 | this.active = 'bar';
17 | this.innerHTML = this.renderPage();
18 | this.addEventListener('my-event', (event)=> {
19 | this.setAttribute('active', event.detail.menuId);
20 | this.active = event.detail.menuId;
21 | });
22 | }
23 |
24 | renderPage() {
25 | return `
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
`;
34 | }
35 |
36 |
37 | attributeChangedCallback(name, oldValue, newValue) {
38 | const isNew = oldValue !== newValue;
39 | if (name === 'active' && isNew) {
40 | this.innerHTML = this.renderPage();
41 | }
42 | }
43 | }
44 | customElements.define('main-layout', MainLayout);
45 |
--------------------------------------------------------------------------------
/pure-web-component-main-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Example of Webcomponent
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/pure-web-component-main-app/src/index.js:
--------------------------------------------------------------------------------
1 | import './components/main-layout';
2 |
--------------------------------------------------------------------------------
/pure-web-component-main-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const {CleanWebpackPlugin} = require('clean-webpack-plugin');
4 | const CopyWebpackPlugin = require('copy-webpack-plugin');
5 |
6 | module.exports = (env, argv)=>({
7 | mode: 'development',
8 | entry: {
9 | app: './src/index.js'
10 | },
11 | devServer: {
12 | contentBase: path.join(__dirname, 'dist'),
13 | historyApiFallback: true
14 | },
15 | devtool: argv.mode === 'production'? 'none' : 'inline-source-map',
16 | externals: {
17 | 'react': {commonjs: 'react'},
18 | 'react-dom': {commonjs: 'react-dom'}
19 | },
20 | plugins: [
21 | new CleanWebpackPlugin(),
22 | new HtmlWebpackPlugin({
23 | template: './src/index.html'
24 | }),
25 | new CopyWebpackPlugin({
26 | patterns: [
27 | {
28 | context: 'node_modules/@webcomponents/webcomponentsjs',
29 | from: '**/*.js',
30 | to: 'webcomponents'
31 | },
32 | {
33 | from: './src/assets/js/*',
34 | to: './',
35 | flatten: true
36 | }
37 | ]
38 | })
39 | ],
40 | output: {
41 | filename: '[name].bundle.js',
42 | path: path.resolve(__dirname, 'dist')
43 | },
44 | module: {
45 | rules: [
46 | {
47 | test: /\.tsx?$/,
48 | use: 'ts-loader',
49 | exclude: /node_modules/
50 | },
51 | {
52 | test: /\.css$/,
53 | include: path.resolve(__dirname, 'src'),
54 | use: [
55 | 'style-loader',
56 | 'css-loader'
57 | ]
58 | },
59 | {test: /\.s[a|c]ss$/, use: [{loader: "style-loader"}, {loader: "css-loader"}, {loader: "sass-loader"}]},
60 | {test: /\.(png|gif|jpg|cur)$/i, loader: 'url-loader', options: {limit: 8192}},
61 | {
62 | test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
63 | loader: 'url-loader',
64 | options: {limit: 10000, mimetype: 'application/font-woff2'}
65 | },
66 | {
67 | test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
68 | loader: 'url-loader',
69 | options: {limit: 10000, mimetype: 'application/font-woff'}
70 | },
71 | {test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'file-loader'}
72 | ]
73 | },
74 | resolve: {
75 | extensions: ['.js', 'jsx']
76 | }
77 | });
--------------------------------------------------------------------------------
/pure-web-component-menu-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pure-web-component-menu-app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --mode production",
8 | "watch": "webpack --watch",
9 | "start": "webpack-dev-server --open"
10 | },
11 | "devDependencies": {
12 | "@webcomponents/webcomponentsjs": "^2.4.4",
13 | "clean-webpack-plugin": "^3.0.0",
14 | "copy-webpack-plugin": "^6.0.3",
15 | "css-loader": "^4.2.2",
16 | "file-loader": "^6.0.0",
17 | "html-webpack-plugin": "^4.3.0",
18 | "sass-loader": "^10.0.1",
19 | "style-loader": "^1.2.1",
20 | "url-loader": "^4.1.0",
21 | "webpack": "^4.44.1",
22 | "webpack-cli": "^3.3.12",
23 | "webpack-dev-server": "^3.11.0"
24 | },
25 | "author": "",
26 | "license": "ISC",
27 | "dependencies": {}
28 | }
29 |
--------------------------------------------------------------------------------
/pure-web-component-menu-app/src/assets/img/290408.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vo-shared/microfrontend-pure-webcomponent/8f2ec837ebb03404e203f751c4d5cf29f681afdf/pure-web-component-menu-app/src/assets/img/290408.png
--------------------------------------------------------------------------------
/pure-web-component-menu-app/src/components/left-menu.js:
--------------------------------------------------------------------------------
1 | export class LeftMenu extends HTMLElement {
2 |
3 | get items() {
4 | return JSON.parse(this.getAttribute('items'));
5 | }
6 | set items(newVal) {
7 | this.setAttribute('items', JSON.stringify(newVal));
8 | }
9 |
10 | get active() {
11 | return this.getAttribute('active');
12 | }
13 | set active(newVal) {
14 | this.setAttribute('active', newVal);
15 | }
16 |
17 | get template() {
18 | const template = document.createElement('template');
19 | template.innerHTML = `
20 |
`;
26 | return template;
27 | }
28 |
29 |
30 | constructor() {
31 | super();
32 | this.attachShadow({
33 | mode: 'open'
34 | });
35 |
36 | this.items = [
37 | {
38 | id: 'bar',
39 | name: 'Bar chart',
40 | },{
41 | id: 'line',
42 | name: 'Line chart'
43 | },{
44 | id: 'radar',
45 | name: 'Radar chart'
46 | },{
47 | id: 'bubble',
48 | name: 'Bubble chart'
49 | },{
50 | id: 'pie',
51 | name: 'Pie chart'
52 | }
53 | ];
54 | this.shadowRoot.appendChild(this.template.content.cloneNode(true));
55 | this.renderChildren();
56 | }
57 |
58 | renderChildren(){
59 | const parent = this.shadowRoot.querySelector('#menu-list');
60 | if(this.items && this.items .length >0) {
61 | this.items.forEach(item => {
62 | const li = document.createElement('li')
63 | li.className = `list-group-item${this.active === item.id?' active' : ''}`;
64 | li.innerText = item.name;
65 | li.key = item.id;
66 | li.addEventListener('click', (event)=> {
67 | this.dispatchEvent(new CustomEvent('my-event', {
68 | bubbles: true,
69 | detail: {
70 | menuId: li.key
71 | }
72 | }));
73 | });
74 | parent.appendChild(li);
75 | });
76 | }
77 | }
78 |
79 |
80 | }
81 | customElements.define('left-menu', LeftMenu);
82 |
--------------------------------------------------------------------------------
/pure-web-component-menu-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Example of Webcomponent
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/pure-web-component-menu-app/src/index.js:
--------------------------------------------------------------------------------
1 | import './components/left-menu';
--------------------------------------------------------------------------------
/pure-web-component-menu-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const {CleanWebpackPlugin} = require('clean-webpack-plugin');
4 | const CopyWebpackPlugin = require('copy-webpack-plugin');
5 |
6 | module.exports = (env, argv)=>({
7 | mode: 'development',
8 | entry: {
9 | app: './src/index.js'
10 | },
11 | devServer: {
12 | contentBase: path.join(__dirname, 'dist'),
13 | historyApiFallback: true
14 | },
15 | devtool: argv.mode === 'production'? 'none' : 'inline-source-map',
16 | externals: {
17 | 'react': {commonjs: 'react'},
18 | 'react-dom': {commonjs: 'react-dom'}
19 | },
20 | plugins: [
21 | new CleanWebpackPlugin(),
22 | new HtmlWebpackPlugin({
23 | template: './src/index.html'
24 | }),
25 | new CopyWebpackPlugin({
26 | patterns: [
27 | {
28 | context: 'node_modules/@webcomponents/webcomponentsjs',
29 | from: '**/*.js',
30 | to: 'webcomponents'
31 | },
32 | {
33 | from: './src/assets/img/*',
34 | to: './',
35 | flatten: true
36 | }
37 | ]
38 | })
39 | ],
40 | output: {
41 | filename: 'menu.bundle.js',
42 | path: path.resolve(__dirname, 'dist')
43 | },
44 | module: {
45 | rules: [
46 | {
47 | test: /\.css$/,
48 | include: path.resolve(__dirname, 'src'),
49 | use: [
50 | 'style-loader',
51 | 'css-loader'
52 | ]
53 | },
54 | {test: /\.s[a|c]ss$/, use: [{loader: "style-loader"}, {loader: "css-loader"}, {loader: "sass-loader"}]},
55 | {test: /\.(png|gif|jpg|cur)$/i, loader: 'url-loader', options: {limit: 8192}},
56 | {
57 | test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
58 | loader: 'url-loader',
59 | options: {limit: 10000, mimetype: 'application/font-woff2'}
60 | },
61 | {
62 | test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
63 | loader: 'url-loader',
64 | options: {limit: 10000, mimetype: 'application/font-woff'}
65 | },
66 | {test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'file-loader'}
67 | ]
68 | },
69 | resolve: {
70 | extensions: ['.js', 'jsx']
71 | }
72 | });
--------------------------------------------------------------------------------