前端 DevOps 实施流程和规范构建流程发布规范使用:https://github.com/conventional-changelog/standard-version
standard-version will then do the following:
Retrieve the current version of your repository by looking at packageFiles, falling back to the last git tag.bump the version in bumpFiles based on your commits.Generates a changelog based on your commits (uses conventional-changelog under the hood).Creates a new commit including your bumpFiles and updated CHANGELOG.Creates a new tag with the new version number.CHANGELOGhttps://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-cli
$ npm install -g conventional-changelog-cli
$ cd my-project
$ conventional-changelog -p angular -i CHANGELOG.md -s规范自动化editorconfig,帮助开发人员定义和维护跨编辑器(或IDE)的统一的代码风格prettier,一个强势武断的代码格式化工具。husky,一个用于 Node.js 项目的快速安装 git hooks 的工具。lint-staged,在 git staged 阶段,执行各种 Linter 的工具。converntional-changelog,根据 Git 提交历史生成 CHANGELOG 的工具。commitLint, 对提交信息进行 Lint 的工具。styleLint,对 CSS 进行 Lint 的工具。remark-lint,使用 Remark 对 Markdown 进行 Lint基于 Husky + LintStaged流程:
待提交的代码 git add 添加到暂存区;执行 git commit;注册到 git 钩子函数的 husky pre-commit 脚本被调用,执行 lint-staged;修改的文件依次执行 lint-staged 定义的任务;lint 失败,则需要等待修复;lint 成功,而执行 commit同理,对于 pre-push 也是如此。代码规范Google JavaScript 规范:Google JavaScript Style Guide , 中文翻译:Google JavaScript 代码风格指南Airbnb JavaScript 规范:Airbnb JavaScript Style Guide() {JavaScript Standard 规范:JavaScript 代码规范,自带 linter & 代码自动修正自定义 LintStyleLint 相关相关的库:
标准:https://github.com/stylelint/stylelint-config-standard ,包含可能报错的 rule,code format 的 css 标准推荐:https://github.com/stylelint/stylelint-config-recommended , 继承于 recommend,包含了一些常见的css书写标准,启用其他规则以强制执行一些 CSS 样式指南中的通用样式约定,包括:The Idiomatic CSS Principles,Google 的 CSS 样式指南,Airbnb 的样式指南和 @mdo 的代码指南。ESLint 示例相关的库:
整合 SonarReact 示例module.exports = {
parser: 'babel-eslint',
extends: ['airbnb', 'prettier', 'plugin:compat/recommended'],
env: {
browser: true,
node: true,
es6: true,
mocha: true,
jest: true,
jasmine: true,
},
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
page: true,
},
rules: {
'react/jsx-filename-extension': [1, { extensions: ['.js'] }],
'react/jsx-wrap-multilines': 0,
'react/prop-types': 0,
'react/forbid-prop-types': 0,
'react/jsx-one-expression-per-line': 0,
'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }],
'import/no-extraneous-dependencies': [
2,
{
optionalDependencies: true,
devDependencies: ['**/tests/**.js', '/mock/**/**.js', '**/**.test.js'],
},
],
'import/no-cycle': 0,
'jsx-a11y/no-noninteractive-element-interactions': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/no-static-element-interactions': 0,
'jsx-a11y/anchor-is-valid': 0,
'linebreak-style': 0,
'jsx-a11y/media-has-caption': 0,
'react/no-array-index-key': 0,
},
settings: {
polyfills: ['fetch', 'Promise', 'Number.isNaN', 'Object.assign', 'Object.entries', 'URL'],
},
}https://eslint.org/https://github.com/ElemeFE/eslint-config-elemefehttps://github.com/AlloyTeam/eslint-config-alloyhttps://github.com/vuejs/eslint-plugin-vuehttps://github.com/yannickcr/eslint-plugin-reacthttps://github.com/typescript-eslint/typescript-eslintundefinedhttps://github.com/SonarSource/eslint-plugin-sonarjshttps://github.com/racodond/sonar-css-pluginundefinedundefinedVue 示例module.exports = {
root: true,
env: {
browser: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:vue/recommended',
'plugin:import/recommended',
process.env.CI ? '' : 'plugin:prettier/recommended',
'prettier',
'prettier/vue',
],
rules: {
eqeqeq: [
'error',
'always',
{
null: 'ignore',
},
],
'consistent-return': "error",
'import/no-unresolved': 'off',
'import/first': 'error',
'import/order': [
'error',
{
'newlines-between': 'always-and-inside-groups',
},
],
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
},
parserOptions: {
parser: 'babel-eslint',
ecmaVersion: 2018,
sourceType: 'module',
},
overrides: [
{
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.{j,t}s?(x)'],
env: {
jest: true,
},
},
],
globals: {
QC: false,
},
noInlineConfig: true,
}TypeScript 示例module.exports = {
root: true,
env: {
browser: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:vue/recommended',
// 'plugin:import/recommended',
'@vue/typescript/recommended',
// '@vue/prettier',
// '@vue/prettier/@typescript-eslint',
],
rules: {
'eqeqeq': [
'error',
'always',
{
null: 'ignore',
},
],
// Best Practices
// 'array-callback-return': 'error',
// 'class-methods-use-this': 'error',
'complexity': ['error', 50],
'curly': 'error',
'consistent-return': 'error',
'eqeqeq': ['error', 'always', { null: 'ignore' }],
'no-else-return': 'error',
'no-extend-native': 'error',
'no-implicit-coercion': 'error',
'no-sequences': 'error',
'no-throw-literal': 'error',
'no-useless-return': 'error',
'no-void': 'error',
'prefer-promise-reject-errors': 'error',
// 'radix': 'error',
'yoda': 'error',
// End of 'Best Practices'
// Stylistic
'array-bracket-newline': ['error', 'consistent'],
'array-bracket-spacing': 'error',
'comma-dangle': ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never"
}],
'eol-last': 'error',
// End of 'Stylistic'
// 'import/no-unresolved': 'off',
// 'import/first': 'error',
// 'import/order': [
// 'error',
// {
// 'newlines-between': 'always-and-inside-groups',
// },
// ],
// 'import/newline-after-import': 'error',
// 'import/no-duplicates': 'error',
'vue/no-v-html': 'off',
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-non-null-assertion': 'off',
'indent': 'off',
'@typescript-eslint/indent': ['error', 2],
'semi': 'off',
'@typescript-eslint/semi': ['error', 'never'],
'quotes': 'off',
'@typescript-eslint/quotes': ['error', 'single'],
},
parserOptions: {
parser: '@typescript-eslint/parser',
},
overrides: [
{
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.{j,t}s?(x)'],
env: {
jest: true,
},
},
{
files: ['vue.config.js'],
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
},
],
globals: {
QC: false,
},
noInlineConfig: true,
}前端测试通用 BDDxCucumberGaugeRobot编程语言支持Java,Ruby,JavaScript 等 13 种语言Java, JavaScript, Ruby 等 6 种语言Python, Java, C支持的系统所有主流系统所有主流系统所有主流系统多语言支持UTF-8UTF-8用户关键字及用例层面支持 UTF-8中文社区支持完善待完善完善ReportJS 不支持 HTML粗粒度细粒度失败时截图不支持支持支持Angular自带
Unit: JasmineE2E: ProtractorVuevue add @vue/unit-jest单元测试(UT)Vue CLI 拥有开箱即用的通过 Jest 或 Mocha 进行单元测试的内置选项。我们还有官方的 Vue Test Utils 提供更多详细的指引和自定义设置。快照测试DOM SnapshotsJest: https://jestjs.io/docs/zh-Hans/next/snapshot-testing
describe('TodoItem snapshot test', () => {
it('first render', () => {
const wrapper = shallowMount(TodoItem, {
propsData: {
item: {
finished: true,
content: 'test TodoItem',
},
},
});
expect(wrapper.html()).toMatchSnapshot();
});
});示例结果:
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
`;Visual SnapshotsWraith is a screenshot comparison tool, created by developers at BBC News.Hermione is a utility for integration testing of web pages using WebdriverIO v4 and Mocha.Differencify is a library for visual regression testing via comparing your local changes with reference screenshots of your website.更多工具:关于前端测试
E2E 测试TestCafeCucumber.jsNightwatchPuppeteerCypressTestCafenpm install -g testcafeimport { Selector } from 'testcafe';
fixture`Getting Started`.page`http://devexpress.github.io/testcafe/example`;
test('My first test', async (t) => {
await t.typeText('#developer-name', 'John Smith').click('#submit-button');
});NightwatchInstall -> Installation
module.exports = {
'Demo test ecosia.org': function (browser) {
browser
.url('https://www.ecosia.org/')
.waitForElementVisible('body')
.assert.titleContains('Ecosia')
.assert.visible('input[type=search]')
.setValue('input[type=search]', 'nightwatch')
.assert.visible('button[type=submit]')
.click('button[type=submit]')
.assert.containsText('.mainline-results', 'Nightwatch.js')
.end();
},
};Puppeteernpm i puppeteerconst puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'example.png' });
await browser.close();
})();Cucumber.jsyarn add -D chai@latest cucumber@latest
npm i -D chai@latest cucumber@latestSteps
# features/simple_math.feature
Feature: Simple maths
In order to do maths
As a developer
I want to increment variables
Scenario: easy maths
Given a variable set to 1
When I increment the variable by 1
Then the variable should contain 2
Scenario Outline: much more complex stuff
Given a variable set to
When I increment the variable by
Then the variable should contain
Examples:
| var | increment | result |
| 100 | 5 | 105 |
| 99 | 1234 | 1333 |
| 12 | 5 | 17 |// features/support/steps.js
const { Given, When, Then } = require('cucumber');
const { expect } = require('chai');
Given('a variable set to {int}', function (number) {
this.setTo(number);
});
When('I increment the variable by {int}', function (number) {
this.incrementBy(number);
});
Then('the variable should contain {int}', function (number) {
expect(this.variable).to.eql(number);
});Cypressnpm install cypress示例:
describe('My First Test', () => {
it('clicking "type" navigates to a new url', () => {
cy.visit('https://example.cypress.io');
cy.contains('type').click();
// Should be on a new URL which includes '/commands/actions'
cy.url().should('include', '/commands/actions');
});
});前端架构拆分方式:
微应用化微前端:微前端微前端架构是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。
由此带来的变化是,这些前端应用可以独立运行、独立开发、独立部署。以及,它们应该可以在共享组件的同时进行并行开发——这些组件可以通过 NPM 或者 Git Tag、Git Submodule 来管理。详细:微前端如何落地
微应用化微应用化与微前端架构相当的类似,它们在开发时都是独立应用,在构建时又可以按照需求单独加载。如果以微前端的单独开发、单独部署、运行时聚合的基本思想来看,微应用化就是微前端的一种实践。只是使用微应用化意味着:我们只能使用唯一的一种前端框架。如果从框架不限的角度来定义,怕是离微前端有些远,不过大团队怕是不会想同时支持多个前端框架。详细见:微前端:微应用化
前端监控参考来源:《前端如何搞监控总结篇》