├── .npmignore
├── .gitignore
├── .vscode
└── settings.json
├── logo.png
├── generator
├── template-ts
│ ├── src
│ │ ├── shims-vue.d.ts
│ │ ├── options
│ │ │ ├── index.ts
│ │ │ ├── App
│ │ │ │ └── App.vue
│ │ │ └── index.html
│ │ ├── popup
│ │ │ ├── index.ts
│ │ │ ├── App
│ │ │ │ └── App.vue
│ │ │ └── index.html
│ │ └── shims-tsx.d.ts
│ └── vue.config.js
├── template-js
│ ├── src
│ │ ├── options
│ │ │ ├── index.js
│ │ │ ├── App
│ │ │ │ └── App.vue
│ │ │ └── index.html
│ │ └── popup
│ │ │ ├── index.js
│ │ │ ├── App
│ │ │ └── App.vue
│ │ │ └── index.html
│ └── vue.config.js
├── index.js
└── generate
│ └── manifest.js
├── prod.sh
├── index.js
├── auto.sh
├── prompts.js
├── package.json
├── LICENSE
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | test-dir
2 | test-prod
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test-dir
2 | test-prod
3 | node_modules
4 | *.log
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": true
3 | }
4 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/superoo7/vue-cli-plugin-chrome-ext/HEAD/logo.png
--------------------------------------------------------------------------------
/generator/template-ts/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/prod.sh:
--------------------------------------------------------------------------------
1 | # /bin/sh
2 |
3 | [ -e test-prod ] && rm -rf test-prod
4 | vue create test-prod -d
5 | (
6 | cd test-prod &&
7 | vue add chrome-ext
8 | )
9 |
--------------------------------------------------------------------------------
/generator/template-js/src/options/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import AppComponent from "./App/App.vue";
3 |
4 | Vue.component("app-component", AppComponent);
5 |
6 | new Vue({
7 | el: "#app",
8 | render: createElement => {
9 | return createElement(AppComponent);
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/generator/template-js/src/popup/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import AppComponent from "./App/App.vue";
3 |
4 | Vue.component("app-component", AppComponent);
5 |
6 | new Vue({
7 | el: "#app",
8 | render: createElement => {
9 | return createElement(AppComponent);
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/generator/template-ts/src/options/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import AppComponent from "./App/App.vue";
3 |
4 | Vue.component("app-component", AppComponent);
5 |
6 | new Vue({
7 | el: "#app",
8 | render: createElement => {
9 | return createElement(AppComponent);
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/generator/template-ts/src/popup/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import AppComponent from "./App/App.vue";
3 |
4 | Vue.component("app-component", AppComponent);
5 |
6 | new Vue({
7 | el: "#app",
8 | render: createElement => {
9 | return createElement(AppComponent);
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/generator/template-ts/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/generator/template-js/src/options/App/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Hello Options
4 |
5 |
6 |
7 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/generator/template-js/src/popup/App/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Hello popup
4 |
5 |
6 |
7 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/generator/template-ts/src/options/App/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Hello Options
4 |
5 |
6 |
7 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/generator/template-ts/src/popup/App/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Hello popup
4 |
5 |
6 |
7 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (api, opts) => {
2 | api.chainWebpack(webpackConfig => {
3 | // remove split chunks for chrome extension, make sure everything in a file
4 | webpackConfig.optimization.delete("splitChunks");
5 | });
6 |
7 | api.configureWebpack(webpackConfig => {});
8 |
9 | api.registerCommand("build-watch", (...args) => {
10 | api.configureWebpack(webpackConfig => {
11 | webpackConfig.watch = true;
12 | });
13 | api.service.run("build", ...args);
14 | });
15 | };
16 |
--------------------------------------------------------------------------------
/auto.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | # https://stackoverflow.com/questions/42308064/check-for-flag-passed-to-a-bash-script-and-process-value
4 | while getopts ":r" opt; do
5 | case $opt in
6 | r)
7 | echo "resetting test-dir" &&
8 | [ -e test-dir ] && rm -rf test-dir &&
9 | vue create test-dir -d
10 | ;;
11 | esac
12 | done
13 |
14 | [ ! -e test-dir ] &&
15 | vue create test-dir -d
16 |
17 | (
18 | cd test-dir &&
19 | # npm uninstall ../
20 | npm install --save-dev ../ &&
21 | vue invoke vue-cli-plugin-chrome-ext --name "test 1" --description "test 2" --version_no "1.0.0" --popup "yes" --script "js"
22 | )
--------------------------------------------------------------------------------
/generator/template-js/src/options/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Options
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/generator/template-js/src/popup/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Options
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/generator/template-ts/src/options/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Options
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/generator/template-ts/src/popup/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Options
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/prompts.js:
--------------------------------------------------------------------------------
1 | module.exports = [{
2 | name: "name",
3 | type: "input",
4 | message: "Name of the Chrome Extension?",
5 | default: "chrome-ext"
6 | },
7 | {
8 | name: "description",
9 | type: "input",
10 | message: "Description for the Chrome Extension?",
11 | default: "chrome extension"
12 | },
13 | {
14 | name: "version_no",
15 | type: "input",
16 | message: "Version for the Chrome Extension?",
17 | default: "0.0.1"
18 | },
19 | {
20 | name: "script",
21 | type: "list",
22 | message: "javascript or typescript?",
23 | choices: ["js", "ts"],
24 | default: "js"
25 | }
26 | ];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-cli-plugin-chrome-ext",
3 | "version": "0.0.5",
4 | "description": "generate chrome extension with vue.js",
5 | "author": "superoo7 ",
6 | "scripts": {},
7 | "dependencies": {},
8 | "devDependencies": {},
9 | "bugs": {
10 | "url": "https://github.com/superoo7/vue-cli-plugin-chrome-ext/issues"
11 | },
12 | "homepage": "https://github.com/superoo7/vue-cli-plugin-chrome-ext#readme",
13 | "keywords": [
14 | "vue",
15 | "vue-cli",
16 | "chrome",
17 | "chrome-extension"
18 | ],
19 | "license": "MIT",
20 | "main": "index.js",
21 | "repository": {
22 | "type": "git",
23 | "url": "git+https://github.com/superoo7/vue-cli-plugin-chrome-ext.git"
24 | }
25 | }
--------------------------------------------------------------------------------
/generator/index.js:
--------------------------------------------------------------------------------
1 | const generateManifest = require("./generate/manifest");
2 | const path = require("path");
3 |
4 | module.exports = (api, options, rootOptions) => {
5 | const ext = options.script;
6 |
7 | // create file
8 | api.render(`./template-${ext}`);
9 |
10 | const extPkg = {
11 | scripts: {
12 | "build-watch": "vue-cli-service build-watch"
13 | },
14 | devDependencies: {
15 | "copy-webpack-plugin": "^4.6.0"
16 | }
17 | };
18 | if (ext === "ts") {
19 | extPkg.devDependencies = {
20 | ...extPkg.devDependencies,
21 | "@types/chrome": "^0.0.75"
22 | };
23 | }
24 | api.extendPackage(extPkg);
25 |
26 | api.onCreateComplete(() => {
27 | // add manifest.json to src file
28 | const manifestPath = api.resolve("./src");
29 | generateManifest(options, manifestPath);
30 | });
31 | };
--------------------------------------------------------------------------------
/generator/template-js/vue.config.js:
--------------------------------------------------------------------------------
1 | const CopyWebpackPlugin = require("copy-webpack-plugin");
2 | const path = require("path");
3 |
4 | // Generate pages object
5 | const pagesObj = {};
6 |
7 | const chromeName = ["popup", "options"];
8 |
9 | chromeName.forEach(name => {
10 | pagesObj[name] = {
11 | entry: `src/${name}/index.js`,
12 | template: "public/index.html",
13 | filename: `${name}.html`
14 | };
15 | });
16 |
17 | const plugins =
18 | process.env.NODE_ENV === "production"
19 | ? [
20 | {
21 | from: path.resolve("src/manifest.production.json"),
22 | to: `${path.resolve("dist")}/manifest.json`
23 | }
24 | ]
25 | : [
26 | {
27 | from: path.resolve("src/manifest.development.json"),
28 | to: `${path.resolve("dist")}/manifest.json`
29 | }
30 | ];
31 |
32 | module.exports = {
33 | pages: pagesObj,
34 | configureWebpack: {
35 | plugins: [CopyWebpackPlugin(plugins)]
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/generator/template-ts/vue.config.js:
--------------------------------------------------------------------------------
1 | const CopyWebpackPlugin = require("copy-webpack-plugin");
2 | const path = require("path");
3 |
4 | // Generate pages object
5 | const pagesObj = {};
6 |
7 | const chromeName = ["popup", "options"];
8 |
9 | chromeName.forEach(name => {
10 | pagesObj[name] = {
11 | entry: `src/${name}/index.ts`,
12 | template: "public/index.html",
13 | filename: `${name}.html`
14 | };
15 | });
16 |
17 | const plugins =
18 | process.env.NODE_ENV === "production"
19 | ? [
20 | {
21 | from: path.resolve("src/manifest.production.json"),
22 | to: `${path.resolve("dist")}/manifest.json`
23 | }
24 | ]
25 | : [
26 | {
27 | from: path.resolve("src/manifest.development.json"),
28 | to: `${path.resolve("dist")}/manifest.json`
29 | }
30 | ];
31 |
32 | module.exports = {
33 | pages: pagesObj,
34 | configureWebpack: {
35 | plugins: [CopyWebpackPlugin(plugins)]
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/generator/generate/manifest.js:
--------------------------------------------------------------------------------
1 | const generateManifest = (options, manifestPath) => {
2 | const fs = require("fs");
3 | const { version_no: version, description, name } = options;
4 | const manifestJson = {
5 | manifest_version: 2,
6 | name,
7 | description,
8 | version,
9 | options_page: "options.html",
10 | browser_action: {
11 | default_popup: "popup.html"
12 | }
13 | };
14 |
15 | // Production build of manifest.json
16 | fs.writeFileSync(
17 | `${manifestPath}/manifest.production.json`,
18 | JSON.stringify(manifestJson, null, 4),
19 | {
20 | encoding: "utf-8"
21 | }
22 | );
23 | // Development build of manifest.json
24 | manifestJson["content_security_policy"] =
25 | "script-src 'self' 'unsafe-eval'; object-src 'self'";
26 | fs.writeFileSync(
27 | `${manifestPath}/manifest.development.json`,
28 | JSON.stringify(manifestJson, null, 4),
29 | {
30 | encoding: "utf-8"
31 | }
32 | );
33 | };
34 |
35 | module.exports = generateManifest;
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Lai Weng Han
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-cli-plugin-chrome-ext
2 |
3 | [](https://www.npmjs.com/package/vue-cli-plugin-chrome-ext)
4 |
5 | Start a chrome extension project with Vue-CLI with ease!
6 |
7 |
8 |
9 | _Logo from FontAwesome_
10 |
11 | ## Installation
12 |
13 | This plugin is meant for using new project for chrome extensions. Tested on default project of Vue, Vue with TypeScript
14 |
15 | ### For TypeScript
16 |
17 | - Create a new project with `vue create test-project`, and select typescript without class-style component syntax
18 | - Then, add this plugin with `vue add chrome-ext`.
19 | - Clean up the repo by removing `src/main.ts`, `src/components`, `public/favicon.ico` and `public/index.html`
20 |
21 | ### For JavaScript
22 |
23 | - Create a new project with `vue create test-project`.
24 | - Then, add this plugin with `vue add chrome-ext`.
25 | - Clean up the repo by removing `src/main.js`, `src/components`, `public/favicon.ico` and `public/index.html`
26 |
27 | ### Run Development mode and Production
28 |
29 | - Run development mode with `npm run build-watch` and a `dist` file will be generated. Install [Extension Reloader](https://chrome.google.com/webstore/detail/extensions-reloader/fimgfedafeadlieiabdeeaodndnlbhid) to reload chrome extensions easily everytime you reload. (take note that when u change manifest.json file, it will not automatically load, you need to remove and add the chrome extensions)
30 | - Build for production `npm run build` and zip it and deploy onto chrome store.
31 |
32 | ## Current feature
33 |
34 | - Generate manifest.json
35 | - Generate popup.html
36 | - Generate options.html
37 | - Emit file out
38 | - Support TypeScript (only generated with `vue add typescript`)
39 |
40 | ## TODO
41 |
42 | ### High Priority
43 |
44 | - Add background script
45 | - Make options to generate certain files
46 |
47 | ### Medium Priority
48 |
49 | - Move over with this [template](https://github.com/posva/vue-plugin-template)
50 | - Clean up src and public file.
51 |
52 | ## Development
53 |
54 | ### Testing
55 |
56 | #### Development
57 |
58 | Currently, testing is done manually with the file `./auto.sh`, by passing `-r` flag, it will delete the initial file generated.
59 |
60 | #### Production
61 |
62 | Test production code in npm as well with `./prod.sh`.
63 |
64 | ### prompts.js
65 |
66 | Vue CLI prompt is based on [inquirer.js](https://github.com/SBoudrias/Inquirer.js) api.
67 |
68 | ## Resources
69 |
70 | - https://itnext.io/how-to-build-a-simple-vue-cli-plugin-a2e1323de1a0
71 |
72 | ## Credit
73 |
74 | - https://github.com/zwenza/vue-cli-plugin-build-watch
75 | - https://github.com/RequireSun/vue-cli-plugin-chrome-extension
76 |
77 | ## License
78 |
79 | MIT
80 |
--------------------------------------------------------------------------------