Hi everybody!
Welcome to the series / tutorial Programming the Chrome extension with Typescript + Vue.js .
In today’s article, we will continue to fix issues when building the Chrome Extension in the previous article . My solution will be to use Webpack like in the Viblo Browser Extension .
First look
Last post, if you notice, yarn serve
, yarn build
actually script alias to vue-cli-service
. Vue CLI Service also uses webpack, but at the present time, customize with webpack still has some limitations:
- Multi entrypoints with webpack
- Config webpack according to document but not receive new webpack configuration
Hopefully in the future we can customize it better.
We use vue-cli-service
to build Vue.js and TypeScript into “pure” js very quickly. So really, what does vue-cli-service
do for us? Here are some typical things:
- Compile Vue.js + TypeScript and extract it into
dist/js/app.[hash].js
- Compile SASS / CSS and extract it into
dist/css/app.[hash].css
- Inject JavaScript and CSS files after successful build into
dist/index.html
file - Package shared libraries between Vue components into
chunk-vendors.[hash].js
. For example: Vue.js, vue-class-component
Install dependency
Install Webpack
Because of the above limitation, I will use Webpack directly without using vue-cli-service as before. We need to configure a bit with the webpack to do the things that vue-cli-service
did above. At the same time solve the problems encountered in the previous article.
Now, let me install the latest version is v4.41.5. And we will continue to install via yarn
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | $ yarn add -D webpack webpack-cli yarn add v1.19.1 <span class="token punctuation">[</span> 1/4 <span class="token punctuation">]</span> Resolving packages <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 2/4 <span class="token punctuation">]</span> Fetching packages <span class="token punctuation">..</span> . info <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> : The platform <span class="token string">"linux"</span> is incompatible with this module. info <span class="token string">" <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> "</span> is an optional dependency and failed compatibility check. Excluding it from installation. info <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> : The platform <span class="token string">"linux"</span> is incompatible with this module. info <span class="token string">" <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> "</span> is an optional dependency and failed compatibility check. Excluding it from installation. <span class="token punctuation">[</span> 3/4 <span class="token punctuation">]</span> Linking dependencies <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 4/4 <span class="token punctuation">]</span> Building fresh packages <span class="token punctuation">..</span> . success Saved lockfile. success Saved 13 new dependencies. info Direct dependencies ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> └─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> Done <span class="token keyword">in</span> 4.80s. |
The
$
character is a command prompt on your terminal, please ignore it.
Install Loaders for webpack
Because I do not use vue-cli-service
, I will need to install some loaders to compile necessary files such as .vue|.ts|.ts|.css|.scss
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ yarn add -D vue-loader ts-loader css-loader file-loader node-sass sass-loader yarn add v1.19.1 <span class="token punctuation">[</span> 1/4 <span class="token punctuation">]</span> Resolving packages <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 2/4 <span class="token punctuation">]</span> Fetching packages <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 3/4 <span class="token punctuation">]</span> Linking dependencies <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 4/4 <span class="token punctuation">]</span> Building fresh packages <span class="token punctuation">..</span> . success Saved lockfile. info Direct dependencies ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> └─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |
Inside:
vue-loader
: compile Vue.jsts-loader
: compile code TypeScriptcss-loader node-sass sass-loader
: for compile CSS, SASS.
Install Webpack Plugins
Next, we install other necessary webpack plugins, mini-css-extract-plugin
, html-webpack-plugin
, copy-webpack-plugin
and cross-env
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ yarn add -D mini-css-extract-plugin html-webpack-plugin copy-webpack-plugin cross-env yarn add v1.19.1 <span class="token punctuation">[</span> 1/4 <span class="token punctuation">]</span> Resolving packages <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 2/4 <span class="token punctuation">]</span> Fetching packages <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 3/4 <span class="token punctuation">]</span> Linking dependencies <span class="token punctuation">..</span> . <span class="token punctuation">[</span> 4/4 <span class="token punctuation">]</span> Building fresh packages <span class="token punctuation">..</span> . success Saved lockfile. success Saved 3 new dependencies. info Direct dependencies ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> ├─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> └─ <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> |
Refactor code & folder structure
Use templates / popup.html
Do not use vue-cli-service
to build, so the public folder is a bit redundant, I will move public/index.html
to templates/popup.html
, and then delete the no longer needed public
folder.
1 2 3 | <span class="token function">mv</span> public/index.html templates/popup.html <span class="token function">rm</span> -rf public |
Remove unused link tags in templates/popup.html
, eventually the content will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> html</span> <span class="token attr-name">lang</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> en <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> head</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> meta</span> <span class="token attr-name">charset</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> utf-8 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> meta</span> <span class="token attr-name">http-equiv</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> X-UA-Compatible <span class="token punctuation">"</span></span> <span class="token attr-name">content</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> IE=edge <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> meta</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> viewport <span class="token punctuation">"</span></span> <span class="token attr-name">content</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> width=device-width,initial-scale=1.0 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> title</span> <span class="token punctuation">></span></span> Prodwarn <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> title</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> head</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> body</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> noscript</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> strong</span> <span class="token punctuation">></span></span> We're sorry but Prodwarn doesn't work properly without JavaScript enabled. Please enable it to continue. <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> strong</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> noscript</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token attr-name">id</span> <span class="token attr-value"><span class="token punctuation">=</span> <span class="token punctuation">"</span> app <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- built files will be auto injected --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> body</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> html</span> <span class="token punctuation">></span></span> |
Update NPM scripts
The build
and serve
commands are also passed via webpack:
1 2 3 4 5 6 7 8 9 | <span class="token property">"scripts"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"serve"</span> <span class="token operator">:</span> <span class="token string">"cross-env NODE_ENV=development webpack -w --hide-modules"</span> <span class="token punctuation">,</span> <span class="token property">"build"</span> <span class="token operator">:</span> <span class="token string">"cross-env NODE_ENV=production webpack --hide-modules"</span> <span class="token punctuation">,</span> <span class="token property">"lint"</span> <span class="token operator">:</span> <span class="token string">"vue-cli-service lint"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token property">"dependencies"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> ... <span class="token punctuation">}</span> |
Inside:
webpack -w
will add a watcher file, which will automatically rebuild the source code whenever the source code file is modifiedcross-env
helps me define environment variable likeNODE_ENV
Now the serve
command no longer serves the web server we access via http: // localhost: 8080 as before, but just a watcher to rebuild the code on our own. Therefore, I will change the command alias from serve
to start
.
1 2 | <span class="token property">"start"</span> <span class="token operator">:</span> <span class="token string">"cross-env NODE_ENV=development webpack -w --hide-modules"</span> <span class="token punctuation">,</span> |
Refactor folder structure
Because normally, a browser extension can have many components, not just the popup. To be a little more neat, we will make a little more neat like the Viblo Browser Extension that is moving the popup code into a separate folder named src/popup
. By the way, we have created a src/content-scripts
folder with a main.ts
file inside with the content:
1 2 3 | <span class="token builtin">console</span> <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'content-scripts are called! ^^'</span> <span class="token punctuation">)</span> |
The src
directory structure will now become:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ tree src/ src/ ├── content-scripts │ └── main.ts └── popup ├── App.vue ├── assets │ └── logo.png ├── components │ └── HelloWorld.vue ├── main.ts ├── shims-tsx.d.ts └── shims-vue.d.ts 4 directories, 7 files |
Webpack configuration
Create webpack.config.js file
As you can see, we are going to setup webpack to compile the code for the two components in the extension:
src/content-scripts
src/popup
We need to compile them into two separate files, so we will need to create two entrypoints for the webpack. Sorry, webpack only supports 1 entrypoint only. Therefore we have to configure separate webpacks for each one.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> contentScripts <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./webpack/content-scripts'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> popup <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./webpack/popup'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">[</span> contentScripts <span class="token punctuation">,</span> popup <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> |
Config webpack for content-scripts
I will have a next article about the components in the browser extension, as well as their functions and effects for people to understand so in this article, let’s temporarily understand content-scripts
will be my scripts to perform operations. with the DOM of a web page you are visiting. For example, when we go to the Viblo page and want to change the background of the page from white to black, that processing code will be placed in content-scripts
and declared in manifest.json
for the browser to execute.
My content scripts are also quite simple because they are TypeScript code, therefore, we only need to use babel-loader
and ts-loader
in webpack. The configuration file will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <span class="token keyword">const</span> <span class="token punctuation">{</span> resolve <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'path'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> mode <span class="token punctuation">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">NODE_ENV</span> <span class="token punctuation">,</span> name <span class="token punctuation">:</span> <span class="token string">'content-scripts'</span> <span class="token punctuation">,</span> entry <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'./src/content-scripts/main.ts'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> output <span class="token punctuation">:</span> <span class="token punctuation">{</span> path <span class="token punctuation">:</span> <span class="token function">resolve</span> <span class="token punctuation">(</span> __dirname <span class="token punctuation">,</span> <span class="token string">'../dist'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> filename <span class="token punctuation">:</span> <span class="token string">'content-scripts/main.js'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> resolve <span class="token punctuation">:</span> <span class="token punctuation">{</span> extensions <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'.js'</span> <span class="token punctuation">,</span> <span class="token string">'.ts'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> alias <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'@'</span> <span class="token punctuation">:</span> <span class="token function">resolve</span> <span class="token punctuation">(</span> __dirname <span class="token punctuation">,</span> <span class="token string">'../src'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> module <span class="token punctuation">:</span> <span class="token punctuation">{</span> rules <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.js$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'babel-loader'</span> <span class="token punctuation">,</span> exclude <span class="token punctuation">:</span> <span class="token regex">/node_modules/</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.ts$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'ts-loader'</span> <span class="token punctuation">,</span> exclude <span class="token punctuation">:</span> <span class="token regex">/node_modules/</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Temporarily we can comment lines 2 and 6 in webpack.config.js
like this to test build:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> contentScripts <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./webpack/content-scripts'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// const popup = require('./webpack/popup');</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">[</span> contentScripts <span class="token punctuation">,</span> <span class="token comment">// popup,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ yarn build yarn run v1.19.1 $ cross-env NODE_ENV <span class="token operator">=</span> production webpack --hide-modules Hash: 44bfd3d4e4a2b06c1184 Version: webpack 4.41.5 Child content-scripts: Hash: 44bfd3d4e4a2b06c1184 Time: 796ms Built at: 01/08/2020 12:23:16 AM Asset Size Chunks Chunk Names content-scripts.js 1020 bytes 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> main Entrypoint main <span class="token operator">=</span> content-scripts.js Done <span class="token keyword">in</span> 1.79s. |
Config webpack for Popup
Popup is a little more config because it has to do a lot of things with Vue.js, TypeScript, Images, SASS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | <span class="token keyword">const</span> <span class="token punctuation">{</span> resolve <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'path'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> HtmlPlugin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'html-webpack-plugin'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// eslint-disable-line</span> <span class="token keyword">const</span> MiniCssExtractPlugin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'mini-css-extract-plugin'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// eslint-disable-line</span> <span class="token keyword">const</span> VueLoaderPlugin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'vue-loader/lib/plugin'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// eslint-disable-line</span> <span class="token keyword">const</span> devMode <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">NODE_ENV</span> <span class="token operator">!==</span> <span class="token string">'production'</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> mode <span class="token punctuation">:</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">NODE_ENV</span> <span class="token punctuation">,</span> name <span class="token punctuation">:</span> <span class="token string">'popup'</span> <span class="token punctuation">,</span> entry <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'./src/popup/main.ts'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> output <span class="token punctuation">:</span> <span class="token punctuation">{</span> path <span class="token punctuation">:</span> <span class="token function">resolve</span> <span class="token punctuation">(</span> __dirname <span class="token punctuation">,</span> <span class="token string">'../dist/popup'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> filename <span class="token punctuation">:</span> <span class="token string">'js/index.js'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> resolve <span class="token punctuation">:</span> <span class="token punctuation">{</span> extensions <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'.js'</span> <span class="token punctuation">,</span> <span class="token string">'.ts'</span> <span class="token punctuation">,</span> <span class="token string">'.vue'</span> <span class="token punctuation">,</span> <span class="token string">'.scss'</span> <span class="token punctuation">,</span> <span class="token string">'.css'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> alias <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">'@'</span> <span class="token punctuation">:</span> <span class="token function">resolve</span> <span class="token punctuation">(</span> __dirname <span class="token punctuation">,</span> <span class="token string">'../src'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> module <span class="token punctuation">:</span> <span class="token punctuation">{</span> rules <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.js$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'babel-loader'</span> <span class="token punctuation">,</span> exclude <span class="token punctuation">:</span> <span class="token regex">/node_modules/</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.ts$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'ts-loader'</span> <span class="token punctuation">,</span> exclude <span class="token punctuation">:</span> <span class="token regex">/node_modules/</span> <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token punctuation">{</span> appendTsSuffixTo <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token regex">/.vue$/</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.vue$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'vue-loader'</span> <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token punctuation">{</span> loaders <span class="token punctuation">:</span> <span class="token punctuation">{</span> scss <span class="token punctuation">:</span> <span class="token string">'vue-style-loader!css-loader!sass-loader'</span> <span class="token punctuation">,</span> sass <span class="token punctuation">:</span> <span class="token string">'vue-style-loader!css-loader!sass-loader?indentedSyntax'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.scss$/</span> <span class="token punctuation">,</span> use <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> loader <span class="token punctuation">:</span> MiniCssExtractPlugin <span class="token punctuation">.</span> loader <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token string">'css-loader'</span> <span class="token punctuation">,</span> <span class="token string">'sass-loader'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.(eot|ttf|woff|woff2)(?S*)?$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'file-loader'</span> <span class="token punctuation">,</span> esModule <span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> test <span class="token punctuation">:</span> <span class="token regex">/.(png|jpg|svg|gif|svg)$/</span> <span class="token punctuation">,</span> loader <span class="token punctuation">:</span> <span class="token string">'file-loader'</span> <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token punctuation">{</span> name <span class="token punctuation">:</span> <span class="token string">'img/[name].[ext]?[hash]'</span> <span class="token punctuation">,</span> esModule <span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> plugins <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">VueLoaderPlugin</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">MiniCssExtractPlugin</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> filename <span class="token punctuation">:</span> devMode <span class="token operator">?</span> <span class="token string">'css/[name].css'</span> <span class="token punctuation">:</span> <span class="token string">'css/[name].[hash].css'</span> <span class="token punctuation">,</span> chunkFilename <span class="token punctuation">:</span> devMode <span class="token operator">?</span> <span class="token string">'css/[id].css'</span> <span class="token punctuation">:</span> <span class="token string">'css/[id].[hash].css'</span> <span class="token punctuation">,</span> ignoreOrder <span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">HtmlPlugin</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> template <span class="token punctuation">:</span> <span class="token function">resolve</span> <span class="token punctuation">(</span> __dirname <span class="token punctuation">,</span> <span class="token string">'../templates/popup.html'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> filename <span class="token punctuation">:</span> <span class="token string">'index.html'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
In particular, I use MiniCssExtractPlugin
to extract css into .css
file, HtmlPlugin
to generate /popup/index.html
file ( /popup/js/index.js
both /popup/js/index.js
and /popup/css/main.css
.
Uncomment the webpack.config.js
comment so we can run the webpack build to try both popup
and content-scripts
:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> contentScripts <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./webpack/content-scripts'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> popup <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'./webpack/popup'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">[</span> contentScripts <span class="token punctuation">,</span> popup <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $ yarn build yarn run v1.15.2 $ cross-env NODE_ENV <span class="token operator">=</span> production webpack --hide-modules Hash: 2ac2f2827d5103f38c5c0ea7ef83af28f19be4fd Version: webpack 4.41.5 Child content-scripts: Hash: 2ac2f2827d5103f38c5c Time: 2773ms Built at: 01/09/2020 12:51:09 PM Asset Size Chunks Chunk Names content-scripts.js 1020 bytes 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> main Entrypoint main <span class="token operator">=</span> content-scripts.js Child popup: Hash: 0ea7ef83af28f19be4fd Time: 4421ms Built at: 01/09/2020 12:51:11 PM Asset Size Chunks Chunk Names css/main.0ea7ef83af28f19be4fd.css 368 bytes 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> <span class="token punctuation">[</span> immutable <span class="token punctuation">]</span> main img/logo.png?82b9c7a5a3f405032b1db71a25f67021 6.69 KiB <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> index.html 619 bytes <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> js/index.js 76.6 KiB 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> main Entrypoint main <span class="token operator">=</span> css/main.0ea7ef83af28f19be4fd.css js/index.js Child html-webpack-plugin <span class="token keyword">for</span> <span class="token string">"index.html"</span> <span class="token keyword">:</span> 1 asset Entrypoint undefined <span class="token operator">=</span> index.html Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/loaders/stylePostLoader.js <span class="token operator">!</span> node_modules/sass-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/index.js??vue-loader-options <span class="token operator">!</span> src/popup/App.vue?vue <span class="token operator">&</span> type <span class="token operator">=</span> style <span class="token operator">&</span> index <span class="token operator">=</span> 0 <span class="token operator">&</span> lang <span class="token operator">=</span> scss <span class="token operator">&</span> <span class="token keyword">:</span> Entrypoint mini-css-extract-plugin <span class="token operator">=</span> * Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/loaders/stylePostLoader.js <span class="token operator">!</span> node_modules/sass-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/index.js??vue-loader-options <span class="token operator">!</span> src/popup/components/HelloWorld.vue?vue <span class="token operator">&</span> type <span class="token operator">=</span> style <span class="token operator">&</span> index <span class="token operator">=</span> 0 <span class="token operator">&</span> id <span class="token operator">=</span> 20a26824 <span class="token operator">&</span> scoped <span class="token operator">=</span> true <span class="token operator">&</span> lang <span class="token operator">=</span> scss <span class="token operator">&</span> <span class="token keyword">:</span> Entrypoint mini-css-extract-plugin <span class="token operator">=</span> * Done <span class="token keyword">in</span> 5.25s. |
So it has succeeded!
Automatically create manifest.json and logo images
At this point, there is one problem that we have not solved is the automatic copy of the manifest.json
file, static
into dist
after each build source code.
This time, we’ll use the copy-webpack-plugin
to automatically generate generate manifest.json
and copy the static
directory each time we build.
If you notice, the two webpack configuration files will have different ouput folders. For popup
it will be dist/popup
and content-scripts
will be dist
. Because manifest.json
and static
files need to be copied to root, this time I will add webpack/content-scripts
webpack configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token keyword">const</span> <span class="token punctuation">{</span> resolve <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'path'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> CopyWebpackPlugin <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'copy-webpack-plugin'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// eslint-disable-line</span> <span class="token keyword">const</span> pkg <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'../package.json'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> manifestTemplate <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'../templates/manifest.json'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">...</span> module <span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> plugins <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">CopyWebpackPlugin</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token keyword">from</span> <span class="token punctuation">:</span> <span class="token string">'./templates/manifest.json'</span> <span class="token punctuation">,</span> to <span class="token punctuation">:</span> <span class="token string">'manifest.json'</span> <span class="token punctuation">,</span> transform <span class="token punctuation">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> manifestTemplate <span class="token punctuation">.</span> version <span class="token operator">=</span> pkg <span class="token punctuation">.</span> version <span class="token punctuation">;</span> <span class="token keyword">return</span> Buffer <span class="token punctuation">.</span> <span class="token keyword">from</span> <span class="token punctuation">(</span> <span class="token constant">JSON</span> <span class="token punctuation">.</span> <span class="token function">stringify</span> <span class="token punctuation">(</span> manifestTemplate <span class="token punctuation">,</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token keyword">from</span> <span class="token punctuation">:</span> <span class="token string">'./static'</span> <span class="token punctuation">,</span> to <span class="token punctuation">:</span> <span class="token string">'static'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> |
The above code uses the transform
function of copy-webpack-plugin
, helping me to insert the new version
name at each release. We only need to return the Buffer
in the transform
function, and our version
will be taken from the package.json
file for release.
Try the last rebuild:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | $ yarn build yarn run v1.15.2 $ cross-env NODE_ENV <span class="token operator">=</span> production webpack --hide-modules Hash: 2ac2f2827d5103f38c5c0ea7ef83af28f19be4fd Version: webpack 4.41.5 Child content-scripts: Hash: 2ac2f2827d5103f38c5c Time: 2104ms Built at: 01/09/2020 1:02:12 PM Asset Size Chunks Chunk Names content-scripts/main.js 1020 bytes 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> main manifest.json 445 bytes <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> static/images/logo-128.png 3.19 KiB <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> static/images/logo-16.png 513 bytes <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> static/images/logo-32.png 1.07 KiB <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> static/images/logo-48.png 1.36 KiB <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> Entrypoint main <span class="token operator">=</span> content-scripts/main.js Child popup: Hash: 0ea7ef83af28f19be4fd Time: 2638ms Built at: 01/09/2020 1:02:12 PM Asset Size Chunks Chunk Names css/main.0ea7ef83af28f19be4fd.css 368 bytes 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> <span class="token punctuation">[</span> immutable <span class="token punctuation">]</span> main img/logo.png?82b9c7a5a3f405032b1db71a25f67021 6.69 KiB <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> index.html 619 bytes <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> js/index.js 76.6 KiB 0 <span class="token punctuation">[</span> emitted <span class="token punctuation">]</span> main Entrypoint main <span class="token operator">=</span> css/main.0ea7ef83af28f19be4fd.css js/index.js Child html-webpack-plugin <span class="token keyword">for</span> <span class="token string">"index.html"</span> <span class="token keyword">:</span> 1 asset Entrypoint undefined <span class="token operator">=</span> index.html Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/loaders/stylePostLoader.js <span class="token operator">!</span> node_modules/sass-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/index.js??vue-loader-options <span class="token operator">!</span> src/popup/App.vue?vue <span class="token operator">&</span> type <span class="token operator">=</span> style <span class="token operator">&</span> index <span class="token operator">=</span> 0 <span class="token operator">&</span> lang <span class="token operator">=</span> scss <span class="token operator">&</span> <span class="token keyword">:</span> Entrypoint mini-css-extract-plugin <span class="token operator">=</span> * Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/loaders/stylePostLoader.js <span class="token operator">!</span> node_modules/sass-loader/dist/cjs.js <span class="token operator">!</span> node_modules/vue-loader/lib/index.js??vue-loader-options <span class="token operator">!</span> src/popup/components/HelloWorld.vue?vue <span class="token operator">&</span> type <span class="token operator">=</span> style <span class="token operator">&</span> index <span class="token operator">=</span> 0 <span class="token operator">&</span> id <span class="token operator">=</span> 20a26824 <span class="token operator">&</span> scoped <span class="token operator">=</span> true <span class="token operator">&</span> lang <span class="token operator">=</span> scss <span class="token operator">&</span> <span class="token keyword">:</span> Entrypoint mini-css-extract-plugin <span class="token operator">=</span> * Done <span class="token keyword">in</span> 3.84s. |
You see in the log build there will be manifest.json
, static/images/logo-*.png
added successfully. However, when opening the extension, the File Not Found
error appears, because we have moved the index.html
file into the popup/index
so the manifest.json
configuration file has become corrupted. Change the link to default_popup: "popup/index.html"
and rebuild it.
So the issues have been resolved. You can then reopen the extension and see that it works normally. If you are following this tutorial and have a problem, please leave a comment for me to discuss. I wish you success and see you later!
TL; DR
Reference links:
- VueLoader Plugin for webpack
- HTML Webpack Plugin
- Mini CSS Webpack Plugin
- Copy Webpack Plugin
- Full source code – Lesson 02
If you find this series interesting and useful, do not forget to share , upvote, folow yourself to read my next articles on Viblo!
You can also subscribe to Vue and Typescript tags on Viblo to get more of the latest posts on these topics on Vbilo! Viblo uses the data that you folow, interested in the system to suggest, so please folow your favorite topics so that the system will recommend more interesting and useful articles from thousands of articles on Viblo that you have never been read!