├── .eslintignore
├── .gitignore
├── .prettierrc.yml
├── .eslintrc.yml
├── commitlint.config.js
├── media
├── icon-large.png
└── icon-small.png
├── src
├── components
│ └── Title.js
├── index.js
├── App.js
├── index.html
├── lib
│ ├── prop.js
│ └── __tests__
│ │ └── prop.test.js
└── webpack-dev-server.js
├── remote-component.config.js
├── webpack.config.js
├── .gitlab-ci.yml
├── .babelrc
├── webpack-demo.config.js
├── LICENSE
├── webpack-dev-server.config.js
├── .vscode
└── launch.json
├── webpack-main.config.js
├── changelog.config.js
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage/
2 | dist/
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /dist
3 | /node_modules
4 |
--------------------------------------------------------------------------------
/.prettierrc.yml:
--------------------------------------------------------------------------------
1 | arrowParens: avoid
2 | tabWidth: 2
3 | trailingComma: none
4 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | extends: ["@paciolan/react"]
2 | rules:
3 | react/prop-types: off
4 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["@commitlint/config-conventional"]
3 | };
4 |
--------------------------------------------------------------------------------
/media/icon-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Paciolan/remote-component-starter/HEAD/media/icon-large.png
--------------------------------------------------------------------------------
/media/icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Paciolan/remote-component-starter/HEAD/media/icon-small.png
--------------------------------------------------------------------------------
/src/components/Title.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export const Title = ({ children }) =>
{children}
;
4 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Entrypoint of the Remote Component.
3 | */
4 | import { App } from "./App";
5 |
6 | export default App;
7 |
--------------------------------------------------------------------------------
/remote-component.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Dependencies for Remote Components
3 | */
4 |
5 | module.exports = {
6 | resolve: {
7 | react: require("react")
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Title } from "./components/Title";
3 |
4 | export const App = ({ name = "World" }) => {
5 | return Hello {name}!;
6 | };
7 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpackMainConfig = require("./webpack-main.config");
2 | const webpackDemoConfig = require("./webpack-demo.config");
3 |
4 | module.exports = [webpackMainConfig, webpackDemoConfig];
5 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/lib/prop.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Safely gets nested properties from an object
3 | * @param {Array} key List of properties
4 | * @param {object} object Object to query
5 | * @returns {*} value
6 | */
7 | export const prop = ([key, ...rest], object) =>
8 | key == null ? object
9 | : object == null ? undefined
10 | : prop(rest, object[key]); // prettier-ignore
11 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | image: paciolanhub/alpine-node-dev:10.15.3c
2 |
3 | stages:
4 | - build
5 |
6 | Build & Test:
7 | stage: build
8 | except:
9 | - tags
10 | before_script:
11 | - npm ci
12 | script:
13 | - npm run build
14 | - npm run lint
15 | - npm run test:coverage -- --colors
16 | artifacts:
17 | expire_in: 1 hour
18 | paths:
19 | - dist/
20 | coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
21 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "useBuiltIns": "usage",
7 | "debug": false
8 | }
9 | ],
10 | "@babel/preset-react"
11 | ],
12 | "plugins": [
13 | [
14 | "@babel/plugin-transform-runtime",
15 | {
16 | "regenerator": true
17 | }
18 | ],
19 | [
20 | "@babel/plugin-proposal-class-properties",
21 | {
22 | "loose": true
23 | }
24 | ],
25 | [
26 | "transform-react-remove-prop-types",
27 | {
28 | "removeImport": true
29 | }
30 | ]
31 | ],
32 | "env": {
33 | "development": {
34 | "sourceMaps": true,
35 | "retainLines": true
36 | },
37 | "test": {
38 | "sourceMaps": true,
39 | "retainLines": true
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/webpack-dev-server.js:
--------------------------------------------------------------------------------
1 | /**
2 | * webpack-dev-server entry point for debugging.
3 | * This file is not bundled with the library during the build process.
4 | */
5 | import { RemoteComponent } from "@paciolan/remote-component";
6 | import React from "react";
7 | import ReactDOM from "react-dom";
8 | import LocalComponent from "./index.js";
9 |
10 | // different paths for localhost vs s3
11 | const url =
12 | process.env.NODE_ENV === "development" ? "/dist/main.js" : "main.js";
13 |
14 | const node = document.getElementById("app");
15 |
16 | const Component = props =>
17 | process.env.NODE_ENV === "development"
18 | ?
19 | : ; // prettier-ignore
20 |
21 | const App = () => (
22 | <>
23 |
24 | >
25 | );
26 |
27 | ReactDOM.render(, node);
28 |
--------------------------------------------------------------------------------
/webpack-demo.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * generates the dist/index.html and dist/demo.js files
3 | * to demo the component.
4 | */
5 |
6 | const HtmlWebpackPlugin = require("html-webpack-plugin");
7 | const path = require("path");
8 | const webpack = require("webpack");
9 |
10 | module.exports = {
11 | plugins: [
12 | new webpack.EnvironmentPlugin({
13 | "process.env.NODE_ENV": process.env.NODE_ENV
14 | }),
15 | new HtmlWebpackPlugin({
16 | template: "./src/index.html"
17 | })
18 | ],
19 | entry: {
20 | demo: "./src/webpack-dev-server.js"
21 | },
22 | module: {
23 | rules: [
24 | {
25 | test: /\.m?js$/,
26 | exclude: /(node_modules|bower_components)/,
27 | use: {
28 | loader: "babel-loader"
29 | }
30 | }
31 | ]
32 | },
33 | resolve: {
34 | alias: {
35 | "remote-component.config.js": path.resolve("./remote-component.config.js")
36 | }
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2019 Paciolan
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/webpack-dev-server.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require("html-webpack-plugin");
2 | const path = require("path");
3 | const webpack = require("webpack");
4 | const config = require("./webpack.config");
5 |
6 | module.exports = {
7 | entry: "./src/webpack-dev-server.js",
8 | plugins: [
9 | ...config[0].plugins,
10 | new HtmlWebpackPlugin({
11 | filename: "index.html",
12 | template: "src/index.html"
13 | }),
14 | new webpack.EnvironmentPlugin({
15 | "process.env.NODE_ENV": process.env.NODE_ENV
16 | }),
17 | new webpack.NamedModulesPlugin(),
18 | new webpack.HotModuleReplacementPlugin()
19 | ],
20 | module: config[0].module,
21 | devServer: {
22 | hot: true,
23 | contentBase: __dirname,
24 | headers: {
25 | "Access-Control-Allow-Origin": "*",
26 | "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
27 | "Access-Control-Allow-Headers":
28 | "X-Requested-With, content-type, Authorization"
29 | }
30 | },
31 | resolve: {
32 | alias: {
33 | "remote-component.config.js": path.resolve("./remote-component.config.js")
34 | }
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "chrome",
9 | "request": "launch",
10 | "name": "Launch Chrome",
11 | "url": "http://localhost:9090",
12 | "webRoot": "${workspaceFolder}",
13 | "sourceMaps": true,
14 | },
15 | {
16 | "name": "Jest", // This is the configuration name you will see in debug sidebar
17 | "type": "node",
18 | "request": "launch",
19 | "port": 9229,
20 | "address": "localhost",
21 | "stopOnEntry": false,
22 | "runtimeExecutable": null,
23 | "env": {
24 | "NODE_ENV": "test"
25 | },
26 | "console": "integratedTerminal",
27 | "runtimeArgs": [
28 | "--inspect-brk", // node v8 use debug-brk if older version of node
29 | "${workspaceRoot}/node_modules/.bin/jest",
30 | "--watch",
31 | "--bail",
32 | "--runInBand"
33 | ],
34 | "cwd": "${workspaceRoot}",
35 | "sourceMaps": true
36 | }
37 | ]
38 | }
--------------------------------------------------------------------------------
/src/lib/__tests__/prop.test.js:
--------------------------------------------------------------------------------
1 | const { prop } = require("../prop");
2 |
3 | describe("lib/prop", () => {
4 | test("prop on undefined returns undefined", () => {
5 | const expected = undefined;
6 | const actual = prop(["a"], undefined);
7 | expect(actual).toBe(expected);
8 | });
9 |
10 | test("prop on null returns undefined", () => {
11 | const expected = undefined;
12 | const actual = prop(["a"], null);
13 | expect(actual).toBe(expected);
14 | });
15 |
16 | test("prop[] returns object", () => {
17 | const expected = {};
18 | const actual = prop([], expected);
19 | expect(actual).toBe(expected);
20 | });
21 |
22 | test("prop[a] returns object[a]", () => {
23 | const expected = "SUCCESS";
24 | const actual = prop(["a"], { a: expected });
25 | expect(actual).toBe(expected);
26 | });
27 |
28 | test("prop missing prop returns undefined", () => {
29 | const expected = undefined;
30 | const actual = prop(["a", "b"], { a: 123 });
31 | expect(actual).toBe(expected);
32 | });
33 |
34 | test("prop nested returns value", () => {
35 | const expected = "SUCCESS";
36 | const actual = prop(["a", "b"], { a: { b: expected } });
37 | expect(actual).toBe(expected);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/webpack-main.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * generates:
3 | * - dist/main.js
4 | * - dist/manifest.json
5 | * - dist/webpack-bundle-analyzer-report.html
6 | */
7 | const webpack = require("webpack");
8 | const WebpackAssetsManifest = require("webpack-assets-manifest");
9 | const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
10 | const remoteComponentConfig = require("./remote-component.config").resolve;
11 |
12 | const externals = Object.keys(remoteComponentConfig).reduce(
13 | (obj, key) => ({ ...obj, [key]: key }),
14 | {}
15 | );
16 |
17 | module.exports = {
18 | plugins: [
19 | new webpack.EnvironmentPlugin({
20 | "process.env.NODE_ENV": process.env.NODE_ENV
21 | }),
22 | new BundleAnalyzerPlugin({
23 | analyzerMode: "static",
24 | openAnalyzer: false,
25 | reportFilename: "webpack-bundle-analyzer-report.html"
26 | }),
27 | new WebpackAssetsManifest()
28 | ],
29 | entry: {
30 | main: "./src/index.js"
31 | },
32 | output: {
33 | libraryTarget: "commonjs"
34 | },
35 | externals: {
36 | ...externals,
37 | "remote-component.config.js": "remote-component.config.js"
38 | },
39 | module: {
40 | rules: [
41 | {
42 | test: /\.m?js$/,
43 | exclude: /(node_modules|bower_components)/,
44 | use: {
45 | loader: "babel-loader"
46 | }
47 | }
48 | ]
49 | }
50 | };
51 |
--------------------------------------------------------------------------------
/changelog.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | list: [
3 | "test",
4 | "feat",
5 | "fix",
6 | "chore",
7 | "docs",
8 | "refactor",
9 | "style",
10 | "ci",
11 | "perf"
12 | ],
13 | maxMessageLength: 64,
14 | minMessageLength: 3,
15 | questions: [
16 | "type",
17 | "scope",
18 | "subject",
19 | "body",
20 | "breaking",
21 | "issues",
22 | "lerna"
23 | ],
24 | scopes: [],
25 | types: {
26 | chore: {
27 | description: "Build process or auxiliary tool changes",
28 | emoji: "🛠️",
29 | value: "chore"
30 | },
31 | ci: {
32 | description: "CI related changes",
33 | emoji: "🤖",
34 | value: "ci"
35 | },
36 | docs: {
37 | description: "Documentation only changes",
38 | emoji: "📚",
39 | value: "docs"
40 | },
41 | feat: {
42 | description: "A new feature",
43 | emoji: "✨",
44 | value: "feat"
45 | },
46 | fix: {
47 | description: "A bug fix",
48 | emoji: "🐛",
49 | value: "fix"
50 | },
51 | perf: {
52 | description: "A code change that improves performance",
53 | emoji: "⚡️",
54 | value: "perf"
55 | },
56 | refactor: {
57 | description: "A code change that neither fixes a bug or adds a feature",
58 | emoji: "💡",
59 | value: "refactor"
60 | },
61 | release: {
62 | description: "Create a release commit",
63 | emoji: "🚀",
64 | value: "release"
65 | },
66 | style: {
67 | description: "Markup, white-space, formatting, missing semi-colons...",
68 | emoji: "🎨",
69 | value: "style"
70 | },
71 | test: {
72 | description: "Adding missing tests",
73 | emoji: "🚨",
74 | value: "test"
75 | }
76 | }
77 | };
78 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@paciolan/remote-component-starter",
3 | "version": "1.0.0-semantic-versioning",
4 | "description": "Remote Component Starter",
5 | "private": true,
6 | "browser": "dist/main.js",
7 | "author": "Paciolan",
8 | "license": "MIT",
9 | "scripts": {
10 | "build": "npm run clean && cross-env NODE_ENV=production webpack --mode production",
11 | "build:dev": "npm run clean && cross-env NODE_ENV=development webpack --mode development",
12 | "webpack-dev-server": "cross-env NODE_ENV=development webpack-dev-server -d --port 9090 --config webpack-dev-server.config.js --open",
13 | "start": "concurrently -n webpack,webpack-dev-server -c green,cyan \"npm run build:dev -- --watch --verbose\" \"npm run webpack-dev-server\"",
14 | "clean": "rimraf dist",
15 | "cz": "git-cz",
16 | "test": "echo no tests",
17 | "test:changed": "npm run test -- --changedSince HEAD",
18 | "test:coverage": "npm run test -- --coverage",
19 | "lint": "eslint ."
20 | },
21 | "dependencies": {
22 | "react": "^16.14.0"
23 | },
24 | "devDependencies": {
25 | "@babel/cli": "^7.12.10",
26 | "@babel/core": "^7.12.10",
27 | "@babel/plugin-proposal-class-properties": "^7.12.1",
28 | "@babel/plugin-transform-runtime": "^7.12.10",
29 | "@babel/preset-env": "^7.12.10",
30 | "@babel/preset-react": "^7.12.10",
31 | "@babel/runtime": "^7.12.5",
32 | "@commitlint/cli": "^11.0.0",
33 | "@commitlint/config-conventional": "^11.0.0",
34 | "@paciolan/eslint-config-react": "^1.0.4",
35 | "@paciolan/remote-component": "^2.10.2",
36 | "babel-eslint": "^10.1.0",
37 | "babel-loader": "^8.2.2",
38 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
39 | "concurrently": "^5.3.0",
40 | "core-js": "^2.6.12",
41 | "cross-env": "^7.0.3",
42 | "eslint": "^7.15.0",
43 | "eslint-config-prettier": "^6.15.0",
44 | "eslint-plugin-babel": "^5.3.1",
45 | "eslint-plugin-prettier": "^3.3.0",
46 | "eslint-plugin-react": "^7.21.5",
47 | "git-cz": "^4.7.6",
48 | "html-webpack-plugin": "^4.5.0",
49 | "husky": "^4.3.6",
50 | "prettier": "^2.2.1",
51 | "react-dom": "^16.14.0",
52 | "regenerator-runtime": "^0.13.7",
53 | "rimraf": "^3.0.2",
54 | "webpack": "^4.44.2",
55 | "webpack-assets-manifest": "^3.1.1",
56 | "webpack-bundle-analyzer": "^3.9.0",
57 | "webpack-cli": "^3.3.12",
58 | "webpack-dev-server": "^3.11.0"
59 | },
60 | "husky": {
61 | "hooks": {
62 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
63 | "pre-commit": "npm run lint && npm run build && npm run test:changed",
64 | "pre-push": "npm run test:coverage"
65 | }
66 | },
67 | "config": {
68 | "commitizen": {
69 | "path": "./node_modules/git-cz"
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Remote Component Starter Kit
2 |
3 | 
4 |
5 | Starter Kit for quickly creating a Remote React Component that can be Remotely Loaded by `@paciolan/remote-component`.
6 |
7 | ## Getting Started
8 |
9 | Clone the repository and initialize your project
10 |
11 | ```bash
12 | # create new repo
13 | mkdir my-component
14 | cd my-component
15 | git init
16 |
17 | # pull the remote component starter kit
18 | git pull https://github.com/Paciolan/remote-component-starter.git --depth=1
19 | git commit --amend -m "chore: 🛠️ pull remote-component-starter"
20 |
21 | # install dependencies
22 | npm ci
23 | ```
24 |
25 | Modify `package.json` and replace the starter kit values with your own.
26 |
27 | - set `name` to the name of your project.
28 | - set `description` to describe your project.
29 | - set `repository` to point to your repository.
30 | - set `license` to reflect the license of your project.
31 |
32 | ## Files
33 |
34 | There are a few important files, one set is used for the bundle, another set for local development.
35 |
36 | - `src/index.js` - Entrypoint of the Remote Component. The component needs to be the `default` export.
37 | - `src/webpack-dev-server.js` - Entrypoint for `webpack-dev-server`. This is only used for development and will not be included in the final bundle.
38 | - `src/index.html` - HTML for `webpack-dev-server`. This is only used for development and will not be included in the final bundle.
39 |
40 | ## Building
41 |
42 | The bundle will be output to the `dist/main.js`.
43 |
44 | ```bash
45 | npm run build
46 | ```
47 |
48 | Create a development build for easier debugging.
49 |
50 | ```bash
51 | npm run build:dev
52 | ```
53 |
54 | ## Debugging
55 |
56 | The component can be debugged locally by first starting `webpack-dev-server`.
57 |
58 | ```bash
59 | npm run start
60 | ```
61 |
62 | Now (using VSCODE), go to the Debug tab, select "Launch Chrome" and start the debugger (F5).
63 |
64 | You should now be able to set breakpoints and step through the code.
65 |
66 | ## Changing the Output
67 |
68 | The bundle as a default will be output to the `dist/main.js`. This can be updated by changing the following two files:
69 |
70 | 1. `entry` in `webpack-main.config.js`. Update the `main` property to a desired output name.
71 |
72 | ```javascript
73 | module.exports = {
74 | ...
75 | entry: {
76 | main: "./src/index.js"
77 | },
78 | ...
79 | };
80 | ```
81 |
82 | 2. `url` variable in `src/webpac-dev-server.js`
83 |
84 | ```javascript
85 | // different paths for localhost vs s3
86 | const url =
87 | global.location.hostname === "localhost" ? "/dist/main.js" : "main.js";
88 | ```
89 |
90 | ## External Dependencies
91 |
92 | The Remote Component is self contained with all of it's dependencies bundled with webpack. Any dependencies that will be provided by the app should be marked as `external` in the `webpack.config.js`.
93 |
94 | In this example, `react` and `prop-types` are added to `externals`. They will not be included in the bundle. The web application is expected to provide these dependencies.
95 |
96 | ```javascript
97 | module.exports = {
98 | output: {
99 | libraryTarget: "commonjs"
100 | },
101 | externals: {
102 | react: "react",
103 | "prop-types": "prop-types"
104 | }
105 | };
106 | ```
107 |
108 | ## Commiting
109 |
110 | Commits are added to the repository with commitizen compatible `git-cz`.
111 |
112 | ```bash
113 | # stage all changes
114 | git add .
115 |
116 | # run commitizen
117 | npm run cz
118 | ```
119 |
120 | ## Contributors
121 |
122 | Joel Thoms (https://twitter.com/joelnet)
123 |
124 | Icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [www.flaticon.com](www.flaticon.com)
125 |
--------------------------------------------------------------------------------