Preface
Simple knowledge points combined with appropriate business scenarios can often achieve unexpected results. This article will use the three most basic front-end knowledge that everyone knows to explain how to help the daily work of the operating lady and the company's 48+ front-end development students, so that their work efficiency can be greatly improved.
You may gain after watching
use vue to write a chrome plug-in from scratch
how to use Object.defineProperty to intercept fetch requests`
How to use the oil monkey script to develop an extension program
some thoughts daily Increasing Efficiency
Example of getting started with oil monkey script
Because the next two gadgets are implemented based on the oil monkey script, so let’s learn about it in advance
What is the oil monkey script?
Script (1612d710d8a0d8 Tampermonkey ) is a popular browser extension that can run user-written extension scripts to achieve various functions, such as removing ads, modifying styles, downloading videos, etc.
How to write an oil monkey script?
1. Install oil monkey
Take chrome browser extension as an example, click here to install
After the installation is complete, you can see this in the upper right corner
2. Add sample script hello world
// ==UserScript==
// @name hello world // 脚本名称
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://juejin.cn/* // 表示怎样的url才执行下面的代码
// @icon https://www.google.com/s2/favicons?domain=juejin.cn
// @grant none
// ==/UserScript==
(function() {
'use strict';
alert('hello world')
// Your code here...
})();
That's right, when you open any https://juejin.cn/*
hello world
will pop up, while other pages such as https://baidu.com
will not.
At this point you have completed one of the simplest oil monkey scripts. Next, let's take a look at using the same simple code to solve a practical problem! O(∩_∩)O
3 lines of code to let SSO automatically log in
What's the question?
1. One day the operating
After an operation, the matter was finally settled, and I was in a beautiful mood.
But she thought to herself, why do I have to log in once for each system, not happy o( ̄ヘ ̄o#)
2. Woke up in the afternoon, the leader asked to change the configuration in the morning start to operate immediately)
But what she didn't expect was that the login page in the morning seemed like she hadn't seen her for a long time, and she had another close contact with the young lady 😭
At this time, her heart has begun to collapse
3. But this is not the end, she will be in this state every day from now on
Where is the pain point?
After reading the animated picture above, I guess you are already scolding your mother for the little sister. What kind of stuff are you doing? It's too rubbish. SSO is a unified login. What are you doing here?
Yes, my heart is the same as you . There are ten thousand grass mud horses
not worthy of being a human being. I don’t do anything for a day. I just jump to the login page and enter the user. I clicked the login button with my name and password, and over time, the first sentence that my friends said when they met was not "Have you eaten?", but "Did you log in?".
But after complaining, we still have to think about how to solve these two pain points through technical means to achieve only need to log in once.
1. After logging in to system A, you need to log in again to other systems.
2. The login time is only 2 hours, after 2 hours, you need to log in
How to solve it?
The root cause is that the company's SSO unified login scheme is designed to be problematic, so they need to be promoted to modify it, but this is a relatively long-term process. Is there any way to make us log in happily in the short term?
Pain point 1: 1. After logging in to system A, it needs to log in again when running to other systems. Can't recover
Pain point 2: only 2 hours. After 2 hours, the need to log in again is unable to recover.
It is not easy for us to directly invade various systems to modify the login logic and modify the login timeliness, but we can do some on the 1612d710d8a574 login page (example)
The key is:
- User name input box
- password input box
- Click the button
Therefore, you can use the oil monkey script to insert the code when DOMContentLoaded to realize automatic login and reduce the manual operation process. The general principle is as follows.
// ==UserScript==
// @name SSO自动登录
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://*.xxx.com/login* // 这里是SSO登录页面地址,表示只有符合这个规则的才注入这段代码
// @grant none
// ==/UserScript==
document.querySelector('#username').value = 'xxx' // 用户名
document.querySelector('#password').value = 'yyy' // 密码
document.querySelector('#login-submit').click() // 自动提交登录
is not too simple, so simple that it is horrible, hateful, and spitting! ! ! , There is no technical content
is too simple, so simple that it is horrible, hateful, and spitting! ! ! , There is no technical content
is not too simple, so simple that it is horrible, hateful, and spitting! ! ! , There is no technical content
Yes, on this 😄, little sister for the first time to help her solve the problem for a long time at night to ask me to eat Spicy, I also boast "technology" Good (
here instead of driving)
Try the effect
The script that does not enable automatic login in the first half of the gif requires manual login, and you can log in automatically when the second half is enabled.
Intercept the fetch request, leaving only the pages you want
What's the question?
Common debugging methods of the front end
- chrome inspect
- vconsole
- weinre
- and many more
These methods have their own advantages and disadvantages. For example, chrome inspect needs to be used over the wall for the first time, which is only applicable to Android; vconsole is not convenient for direct debugging styles; weinre is only suitable for debugging styles.
For these reasons, the company developed a remote debugging tool a long time ago, which can easily add and delete DOM structure, debug style, view request, and view application modification to take effect immediately on the phone after
remote debugging platform use process
His usage process is probably like this
Open remote debugging page list
This page contains a link to the debugging page opened by everyone in the
hundreds of
- Click on the page you want to debug, you can enter debugging like chrome console
After reading the process, you should probably know where the problem is. The remote debugging page list contains not only my own pages, but also many others, which makes it difficult to quickly find the page you want to debug.
How to solve it?
problem analysis
Is there any way I can quickly find the page I want to debug? In fact, by observing and parsing this page, you will find that the list is
- Obtained by sending a request
- Device keyword included in the response
Interception request
So clever you have guessed, we can intercept the fetch
Object.defineProperty
, filter the device so that only the device we specify is in the list ( after all, the device debugged during the usual development is basically fixed, and the probability of the device being exactly the same is very low. Yes, so specifying a device actually uniquely identifies itself) page.
How to do it in detail?
// ==UserScript==
// @name 前端远程调试设备过滤
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://chii-fe.xxx.com/ // 指定脚本生效的页面
// @grant none
// @run-at document-start // 注意这里,脚本注入的时机是document-start
// ==/UserScript==
;(() => {
const replaceRe = /\s*/g
// 在这里设置设备白名单
const DEVICE_WHITE_LIST = [
'Xiaomi MI 8',
'iPhone9,2',
].map((it) => it.replace(replaceRe, '').toLowerCase())
const originFetch = window.fetch
const recordListUrl = 'record-list'
const filterData = (source) => {
// 数据过滤,返回DEVICE_WHITE_LIST指定的设备的数据
// 详细过程省略
return data
}
// 拦截fetch请求
Object.defineProperty(window, 'fetch', {
configurable: true,
enumerable: true,
get () {
return function (url, options) {
return originFetch(url, options).then((response) => {
// 只处理指定的url
if (url.includes(recordListUrl)) {
if (response.clone) {
const cloneRes = response.clone()
return new Promise((resolve, reject) => {
resolve({
text: () => {
return cloneRes.json().then(json => {
return filterData(JSON.stringify(json))
});
}
})
})
}
}
return response
})
}
}
})
})()
Try the effect
As you can see from the figure below, there are 37 pages before filtering, and only 3 are left after filtering. You can find the page you want to debug in an instant, and you no longer have to look for your own one from hundreds of pages!
Helping the company's 45+ front-end development-the beginning and end of chrome plug-ins
One-click setting of ua through the plug-in simulates the user login status and improves development efficiency.
Look at the result first
plug-in usage
plug-in usage results
Team 48+ friends are also using it
Background and problems
There are many scenarios in the daily c-side business that require the user log in before they can proceed normally, and the development phase is basically developed through chrome simulation of mobile devices, so it often involves simulating user login in the chrome browser, which involves the following three Step ( this step is more cumbersome).
Note: Keeping the user's login status is generally through cookies, but also through headers. For example, our company rewrites ua to do
Get ua: Go to the company's UA generation platform and enter the mobile phone number to generate ua
add ua: copy ua to chrome devtool
set/modify device
use ua: select the newly added ua, refresh the page, re-develop and debug
Look at a conversation
The girl who just graduated in 1998 next door:
expired again, who squeezed me down again?
Okay, wait a while, I’ll change my account to test
so troublesome! It takes so many steps to simulate a user's information, which is so annoying! ! !
Me, curious uncle:
Under "careful" understanding, she is working on an h5 activity project. The scene is complex and involves many states. You need to use different accounts for testing.
simulate one or two users, but at the moment, my lady has tested so many scenes and has simulated many (anyone will be annoyed)
company’s login system is single sign-on. An account that has finally been simulated may be used by others, but the result is rejected again. I have to regenerate it. I TM
Seeing her crying little eyes, as a friendly neighbor at the next table, I only have one thing in my mind at the moment...! Help her solve this annoying problem.
Analyze and solve problems
Through the above introduction, you should be able to feel the troubles when we need to switch accounts frequently for testing during the development stage. The relatively cumbersome ua generation process has caused it to be a time-consuming and laborious trouble
Is there any way to improve our development efficiency and don't waste it on this kind of thing? Do it step by step together
are the
Provide a convenient way to simulate ua to help improve development efficiency.
Basic appeal: In the local development stage, I hope that there will be more convenient way to simulate user login
Multiple accounts: A project requires multiple accounts, and the accounts between different projects can be shared or different
designated domain: only the designated
domain is required to simulate ua, which cannot affect the normal use of the browser
Expiration processing: After the account expires, it can be generated actively without manual reacquiring
how to solve
Requirement 1: Combining with the previous generation ua stage, we can in some way allow users to generate ua directly on the current page without jumping out, one-click setting to omit the manual process
Requirement 2: Provide multi-account management function, can directly select switch ua
Requirement 3: Restrict the specified domain, the ua will take effect
Requirement 4: When an expired account is used, it can be regenerated with one click
is a chrome plug-in
- sent by the ajax request in the browser cannot be modified directly, but the chrome plug-in can modify the requested ua ( is a very important point )
- The chrome plug-in popup mode can be opened directly on the current page without jumping out of the development page, reducing the jumping out process
Write a chrome plugin from scratch with vue
For space reasons, here is only a simple introduction at the sample level. If you want to learn more about the writing of chrome plug-ins, you can refer
Start with a small example
Next, we will take the following page as an example to illustrate how to write it in vue.
Basic functions
- bottom tab switching area :
viewA
,viewB
,viewC
- Intermediate content area : Switch view A, B, C to display the corresponding page
content part
With the help of the Chrome browser to insert scripts into web pages, we will demonstrate how to insert scripts and play a hello world
and background communication part
The popup completes the user's main interaction, click on the viewA page to get the customized ua information
modify the ajax request ua part
Will demonstrate if the request header is modified through the chrome plug-in
1. Understand the composition of a chrome plug-in
- manifest.json
- background script
- content script
- popup
1. manifest.json
Almost everything must be declared here, permissions, resources, pages, etc.
{
"manifest_version": 2, // 清单文件的版本,这个必须写
"name": "hello vue extend", // 插件的名称,等会我们写的插件名字就叫hello vue extend
"description": "hello vue extend", // 插件描述
"version": "0.0.1", // 插件的版本
// 图标,写一个也行
"icons": {
"48": "img/logo.png"
},
// 浏览器右上角图标设置,browser_action、page_action、app必须三选一
"browser_action": {
"default_icon": "img/logo.png",
"default_title": "hello vue extend",
"default_popup": "popup.html"
},
// 一些常驻的后台JS或后台页面
"background": {
"scripts": [
"js/hot-reload.js",
"js/background.js"
]
},
// 需要直接注入页面的JS
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["js/content.js"],
"run_at": "document_start"
}],
// devtools页面入口,注意只能指向一个HTML文件
"devtools_page": "devcreate.html",
// Chrome40以前的插件配置页写法
"options_page": "options.html",
// 权限申请
"permissions": [
"storage",
"webRequest",
"tabs",
"webRequestBlocking",
"<all_urls>"
]
}
2. background script
The background can be considered as a resident page, with high permissions, almost all APIs can be called, and it can communicate with popups, content scripts, etc.
3. content script
A form of chrome plug-in injecting scripts into the page (both js and css are available)
4. popup
popup
is a small window webpage that opens when you click on thebrowser_action
orpage_action
icon. The webpage will be closed when the focus leaves the webpage.
For example, we want to use vue to make the page.
2. Rewrite vue.config.js
The structure of manifest.json's file reference basically determines the file path after packaging
packaged path
// dist目录用来chrome扩展导入
├── dist
│ ├── favicon.ico
│ ├── img
│ │ └── logo.png
│ ├── js
│ │ ├── background.js
│ │ ├── chunk-vendors.js
│ │ ├── content.js
│ │ ├── hot-reload.js
│ │ └── popup.js
│ ├── manifest.json
│ └── popup.html
source directory
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── js
│ └── hot-reload.js
├── src
│ ├── assets
│ │ ├── 01.png
│ │ ├── disabled.png
│ │ └── logo.png
│ ├── background
│ │ └── background.js
│ ├── content
│ │ └── content.js
│ ├── manifest.json
│ ├── popup
│ │ ├── App.vue
│ │ ├── main.js
│ │ ├── router.js
│ │ └── views
│ │ ├── viewA.vue
│ │ ├── viewB.vue
│ │ └── viewC.vue
│ └── utils
│ ├── base.js
│ ├── fixCaton.js
│ └── storage.js
└── vue.config.js
modify vue.config.js
The main needs to be modified slightly to become multi-page packaging, pay attention to the output directory structure.
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path')
// 这里考虑可以添加多页
const pagesObj = {}
const chromeName = ['popup']
const plugins = [
{
from: path.resolve('src/manifest.json'),
to: `${path.resolve('dist')}/manifest.json`
},
{
from: path.resolve('src/assets/logo.png'),
to: `${path.resolve('dist')}/img/logo.png`
},
{
from: path.resolve('src/background/background.js'),
to: `${path.resolve('dist')}/js/background.js`
},
{
from: path.resolve('src/content/content.js'),
to: `${path.resolve('dist')}/js/content.js`
},
]
chromeName.forEach(name => {
pagesObj[name] = {
css: {
loaderOptions: {
less: {
modifyVars: {},
javascriptEnabled: true
}
}
},
entry: `src/${name}/main.js`,
filename: `${name}.html`
}
})
const vueConfig = {
lintOnSave:false, //关闭eslint检查
pages: pagesObj,
configureWebpack: {
entry: {},
output: {
filename: 'js/[name].js'
},
plugins: [new CopyWebpackPlugin(plugins)]
},
filenameHashing: false,
productionSourceMap: false
}
module.exports = vueConfig
3. Hot refresh
We hope that after modifying the plug-in source code for packaging, the page corresponding to the chrome plug-in can be actively updated. Why is it called hot refresh instead of hot update? Because it actually refreshes the page globally and does not save the state.
Here is a recommended solution on github crx-hotreload
4. Complete the small example
File directory structure
├── popup
│ ├── App.vue
│ ├── main.js
│ ├── router.js
│ └── views
│ ├── viewA.vue
│ ├── viewB.vue
│ └── viewC.vue
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
router.js
import Vue from 'vue'
import Router from 'vue-router'
import ViewA from './views/viewA.vue'
import ViewB from './views/viewB.vue'
import ViewC from './views/viewC.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
redirect: '/view/a'
},
{
path: '/view/a',
name: 'viewA',
component: ViewA,
},
{
path: '/view/b',
name: 'viewB',
component: ViewB,
},
{
path: '/view/c',
name: 'viewC',
component: ViewC,
},
]
})
App.vue
<template>
<div id="app">
<div class="app-router">
<router-view />
</div>
<div class="app-tab">
<div class="app-tab-item" v-for="(tabName, i) in tabs" :key="i" @click="onToView(tabName)">
{{ tabName }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
tabs: [
'viewA',
'viewB',
'viewC',
]
}
},
methods: {
onToView (name) {
this.$router.push({
name
})
}
}
}
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
width: 375px;
height: 200px;
padding: 15px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
flex-direction: column;
.app-router{
flex: 1;
}
.app-tab{
display: flex;
align-items: center;
justify-content: space-between;
.app-tab-item{
font-size: 16px;
color: coral;
cursor: pointer;
}
}
}
</style>
viewA、viewB、viewC
The three pages are basically the same. Only the background color and the copy content are different. Here I will only post the code of viewA.
It should be noted that the popup and background will be demonstrated here, and the background background data is obtained through the sendMessage method.
<template>
<div class="view-a">我是A页面
<button @click="onGetCUstomUa">获取自定义ua</button>
</div>
</template>
<script>
export default {
name: 'viewA',
methods: {
onGetCUstomUa () {
chrome.runtime.sendMessage({type: 'getCustomUserAgent'}, function(response) {
alert(JSON.stringify(response))
})
}
}
}
</script>
<style lang="less">
.view-a{
background-color: cadetblue;
height: 100%;
font-size: 60px;
}
</style>
background.js
const customUa = 'hello world ua'
// 请求发送前拦截
const onBeforeSendCallback = (details) => {
for (var i = 0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name === 'User-Agent') {
details.requestHeaders.splice(i, 1);
break;
}
}
// 修改请求UA为hello world ua
details.requestHeaders.push({
name: 'User-Agent',
value: customUa
});
return { requestHeaders: details.requestHeaders };
}
// 前面的sendMessage获取getCustomUserAgent,会被这里监听
const onRuntimeMessageListener = () => {
chrome.runtime.onMessage.addListener(function (msg, sender, callback) {
if (msg.type === 'getCustomUserAgent') {
callback({
customUa
});
}
});
}
const init = () => {
onRuntimeMessageListener()
onBeforeSendHeadersListener()
}
init()
content.js
Demonstrate how to insert code into a web page
function setScript({ code = '', needRemove = true } = params) {
let textNode = document.createTextNode(code)
let script = document.createElement('script')
script.appendChild(textNode)
script.remove()
let parentNode = document.head || document.documentElement
parentNode.appendChild(script)
needRemove && parentNode.removeChild(script)
}
setScript({
code: `alert ('hello world')`,
})
About one-click setup ua plugin
Generally speaking, it is not the same as the small example, but the function is relatively complicated, which will involve
- Data local storage
chrome.storage.sync.get|set
,chrome.tabs.query
and other API - Popup and background communication, content and background communication
- Intercept request to modify UA
- The rest is roughly the conventional vue code writing!
The detailed code implementation is not posted here.
Some thoughts on daily efficiency improvement
During our work, we will encounter some problems that hinder us from improving work efficiency. These problems may be due to the unreasonable design of the old scheme, or the smelly and long process, or the existing functions that do not meet the new requirements. Wait, if you can do these points, it will not only help your growth, but also contribute to the team.
mentality: Found the problem and actively try to solve the problem, not being a bystander
Keep learning ability: After discovering the problem, if the solution is not in your knowledge reserve, you must try to learn new things ( before writing a one-click setting of the UA plugin) , Out of the comfort zone, will learn more
Keep an enthusiastic attitude: everyone encounters different problems, take the initiative to discuss with colleagues or friends, and stretch out your hands when needed
- 1612d710d8caa2 Execution ability
that affect efficiency (for example, there are others) as the devil, act immediately to reach the devil, don’t delay
Learn to promote: Maybe the plug-in you wrote at the beginning just solved your own problems, but the same working environment may be encountered by others, so learn to share and promote it outside.
Meet bye
The above is all the content of this article! Good night everyone 🌛 and see you next time.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。