├── .mocharc.yaml ├── src ├── utils │ ├── index.js │ └── index.ts ├── api │ ├── index.js │ └── index.ts ├── styles │ ├── val.less │ ├── val.scss │ └── reset.css ├── components │ ├── Hello │ │ ├── hello.scss │ │ ├── hello.less │ │ ├── index.jsx │ │ └── index.tsx │ └── Loading │ │ ├── index.jsx │ │ └── index.tsx ├── constance │ ├── index.js │ └── index.ts ├── store │ ├── redux │ │ ├── types.ts │ │ ├── mutation-types.js │ │ ├── mutation-types.ts │ │ ├── actions │ │ │ ├── index.js │ │ │ ├── index.ts │ │ │ ├── home.js │ │ │ └── home.ts │ │ ├── reducers │ │ │ ├── index.js │ │ │ ├── index.ts │ │ │ ├── home.js │ │ │ └── home.ts │ │ ├── index.js │ │ └── index.ts │ └── mobx │ │ ├── index.js │ │ ├── index.ts │ │ ├── modules │ │ ├── home.js │ │ └── home.ts │ │ ├── context.js │ │ └── context.ts ├── assets │ └── favicon.ico ├── pages │ └── Home │ │ ├── home.less │ │ ├── home.scss │ │ ├── index.jsx │ │ └── index.tsx ├── router │ ├── map.js │ ├── map.ts │ ├── index.jsx │ └── index.tsx ├── app.jsx ├── app.tsx ├── index.jsx └── index.tsx ├── .mocharc.json ├── .gitignore ├── test ├── index.js └── index.ts ├── index.html ├── README.md ├── babel.config.js ├── commitlint.config.js ├── config ├── webpack.dev.js ├── webpack.prod.js └── webpack.common.js ├── templates.ignore ├── tsconfig.json └── package.json /.mocharc.yaml: -------------------------------------------------------------------------------- 1 | require: '@babel/register' -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | // api 2 | export const BASE_URL = '' 3 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | // api 2 | export const BASE_URL = '' 3 | -------------------------------------------------------------------------------- /src/styles/val.less: -------------------------------------------------------------------------------- 1 | @project_prefix: react-app; 2 | 3 | @primary_color: #0099FF; -------------------------------------------------------------------------------- /src/styles/val.scss: -------------------------------------------------------------------------------- 1 | $project_prefix: 'react-app'; 2 | 3 | $primary_color: #0099FF; 4 | -------------------------------------------------------------------------------- /src/components/Hello/hello.scss: -------------------------------------------------------------------------------- 1 | .#{$project_prefix}-comp-hello { 2 | color: $primary_color; 3 | } -------------------------------------------------------------------------------- /src/components/Hello/hello.less: -------------------------------------------------------------------------------- 1 | .@{project_prefix}-comp-hello { 2 | color: @primary_color; 3 | } 4 | -------------------------------------------------------------------------------- /src/constance/index.js: -------------------------------------------------------------------------------- 1 | export const PROJECT_NAME = 'react-app' 2 | export const DEFAULT_TITLE = '首页' -------------------------------------------------------------------------------- /src/constance/index.ts: -------------------------------------------------------------------------------- 1 | export const PROJECT_NAME = 'react-app' 2 | export const DEFAULT_TITLE = '首页' -------------------------------------------------------------------------------- /src/store/redux/types.ts: -------------------------------------------------------------------------------- 1 | export interface IActionProps { 2 | type: String 3 | data: T 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IFmiss/tiga-template-react/master/src/assets/favicon.ico -------------------------------------------------------------------------------- /src/store/redux/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_COUNT = 'ADD_COUNT' 2 | export const REDUCE_COUNT = 'REDUCE_COUNT' 3 | -------------------------------------------------------------------------------- /src/store/redux/mutation-types.ts: -------------------------------------------------------------------------------- 1 | export const ADD_COUNT = 'ADD_COUNT' 2 | export const REDUCE_COUNT = 'REDUCE_COUNT' 3 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extension": ["ts"], 4 | "spec": "test/**/*.ts", 5 | "require": "ts-node/register" 6 | } 7 | -------------------------------------------------------------------------------- /src/store/mobx/index.js: -------------------------------------------------------------------------------- 1 | import HomeModule from './modules/Home' 2 | 3 | const store = { 4 | homeStore: new HomeModule() 5 | } 6 | 7 | export default store 8 | -------------------------------------------------------------------------------- /src/store/mobx/index.ts: -------------------------------------------------------------------------------- 1 | import HomeModule from './modules/home' 2 | 3 | const store = { 4 | homeStore: new HomeModule() 5 | } 6 | 7 | export default store 8 | -------------------------------------------------------------------------------- /src/pages/Home/home.less: -------------------------------------------------------------------------------- 1 | .home { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | flex-direction: column; 6 | 7 | div, span { 8 | padding: 15px 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/Home/home.scss: -------------------------------------------------------------------------------- 1 | .home { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | flex-direction: column; 6 | 7 | div, span { 8 | padding: 15px 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/store/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | bindActionCreators 3 | } from 'redux' 4 | import * as HomeAction from './home' 5 | 6 | export default dispatch => bindActionCreators({ 7 | ...HomeAction 8 | }, dispatch) 9 | -------------------------------------------------------------------------------- /src/components/Loading/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect 3 | } from 'react' 4 | 5 | const Loading = () => { 6 | return ( 7 |
loading...
8 | ) 9 | } 10 | 11 | export default Loading 12 | -------------------------------------------------------------------------------- /src/store/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | combineReducers 3 | } from 'redux' 4 | 5 | import HomeReducer from './home' 6 | 7 | const ReducerInfo = combineReducers({ 8 | home: HomeReducer 9 | }) 10 | 11 | export default ReducerInfo 12 | -------------------------------------------------------------------------------- /src/store/redux/reducers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineReducers 3 | } from 'redux' 4 | 5 | import HomeReducer from './home' 6 | 7 | const ReducerInfo = combineReducers({ 8 | home: HomeReducer 9 | }) 10 | 11 | export default ReducerInfo 12 | -------------------------------------------------------------------------------- /src/store/redux/actions/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | bindActionCreators, 3 | Dispatch 4 | } from 'redux' 5 | import * as HomeAction from './home' 6 | 7 | export default (dispatch: Dispatch) => bindActionCreators({ 8 | ...HomeAction 9 | }, dispatch) 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | package-lock.json 8 | yarn.lock 9 | 10 | # Editor directories and files 11 | .idea 12 | .vscode 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | -------------------------------------------------------------------------------- /src/components/Loading/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect 3 | } from 'react' 4 | 5 | interface ILoadingProps {} 6 | 7 | const Loading: React.FC = () => { 8 | return ( 9 |
loading...
10 | ) 11 | } 12 | 13 | export default Loading 14 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const { 2 | assert 3 | } = require('chai') 4 | 5 | describe('Array', function() { 6 | describe('#indexOf()', function() { 7 | it('should return -1 when the value is not present', function() { 8 | assert.equal([1, 2, 3].indexOf(4), -1); 9 | }) 10 | }) 11 | }) -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | const { 2 | assert 3 | } = require('chai') 4 | 5 | describe('Array', function() { 6 | describe('#indexOf()', function() { 7 | it('should return -1 when the value is not present', function() { 8 | assert.equal([1, 2, 3].indexOf(4), -1) 9 | }) 10 | }) 11 | }) -------------------------------------------------------------------------------- /src/store/mobx/modules/home.js: -------------------------------------------------------------------------------- 1 | import { 2 | observable, 3 | computed, 4 | action 5 | } from 'mobx' 6 | 7 | export default class HomeModule { 8 | @observable 9 | count = 0 10 | 11 | @action 12 | addCount () { 13 | this.count++ 14 | } 15 | 16 | @action 17 | reduceCount () { 18 | this.count-- 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/store/redux/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | createStore, applyMiddleware 3 | } from 'redux' 4 | 5 | import mainReducer from './reducers/index' 6 | 7 | import thunkMiddleware from 'redux-thunk' 8 | 9 | const store = createStore( 10 | mainReducer, 11 | applyMiddleware( 12 | thunkMiddleware 13 | ) 14 | ) 15 | 16 | export default store 17 | -------------------------------------------------------------------------------- /src/store/redux/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createStore, applyMiddleware 3 | } from 'redux' 4 | 5 | import mainReducer from './reducers/index' 6 | 7 | import thunkMiddleware from 'redux-thunk' 8 | 9 | const store = createStore( 10 | mainReducer, 11 | applyMiddleware( 12 | thunkMiddleware 13 | ) 14 | ) 15 | 16 | export default store 17 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /src/store/mobx/context.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | useContext 3 | } from 'react' 4 | import store from './index' 5 | 6 | export const context = React.createContext(store) 7 | 8 | export const useStore = () => { 9 | const s = useContext(context) 10 | if (!s) { 11 | throw new Error('useStore must be used within a StoreProvider.') 12 | } 13 | return s 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/store/mobx/context.ts: -------------------------------------------------------------------------------- 1 | import React, { 2 | useContext 3 | } from 'react' 4 | import store from './index' 5 | 6 | export const context = React.createContext(store) 7 | 8 | export const useStore = () => { 9 | const s = useContext(context) 10 | if (!s) { 11 | throw new Error('useStore must be used within a StoreProvider.') 12 | } 13 | return s 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/store/mobx/modules/home.ts: -------------------------------------------------------------------------------- 1 | import { 2 | observable, 3 | computed, 4 | action 5 | } from 'mobx' 6 | 7 | export default class HomeModule { 8 | @observable 9 | count: number = 0 10 | 11 | @action 12 | addCount () { 13 | console.log(this) 14 | this.count++ 15 | } 16 | 17 | @action 18 | reduceCount () { 19 | this.count-- 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/store/redux/actions/home.js: -------------------------------------------------------------------------------- 1 | import * as types from '@store/mutation-types' 2 | 3 | export function addCount () { 4 | return dispatch => { 5 | dispatch({ 6 | type: types.ADD_COUNT, 7 | data: 1 8 | }) 9 | } 10 | } 11 | 12 | export function reduceCount () { 13 | return dispatch => { 14 | dispatch({ 15 | type: types.REDUCE_COUNT, 16 | data: 1 17 | }) 18 | } 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/router/map.js: -------------------------------------------------------------------------------- 1 | import Loadable from 'react-loadable'; 2 | import Loading from '../components/Loading'; 3 | 4 | const Home = Loadable({ 5 | loader: () => import('@pages/Home'), 6 | loading: Loading 7 | }) 8 | 9 | const routes = [{ 10 | name: 'home', 11 | path: '/home', 12 | component: Home, 13 | meta: { 14 | title: '首页' 15 | } 16 | }, { 17 | name: 'home', 18 | redirect: true 19 | }]; 20 | 21 | export default routes; 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # {{name}} 2 | {{description}} 3 | 基于React 搭建的单页应用 4 | 内置以下已创建功能 5 | - [x] 支持 css 预处理 less, scss,并配置全局变量管理 6 | - [x] 支持 typescript 环境 7 | - [x] 支持react 数据状态管理 redux, mobx 8 | - [x] 支持路由可配置,快速创建页面路由组件 9 | - [x] 支持单元测试 10 | - [x] 支持git hook 11 | - [] 内置 d-utils 支持 tree-shaking 12 | 13 | ### ⏬安装依赖 14 | ```code 15 | yarn 16 | ``` 17 | 18 | ### 🚀启动项目 19 | ```code 20 | yarn dev 21 | ``` 22 | 23 | ### 📦打包项目 24 | ```code 25 | yarn build 26 | ``` 27 | -------------------------------------------------------------------------------- /src/store/redux/actions/home.ts: -------------------------------------------------------------------------------- 1 | import * as types from '@store/mutation-types' 2 | 3 | export function addCount (): Function { 4 | return (dispatch: Function) => { 5 | dispatch({ 6 | type: types.ADD_COUNT, 7 | data: 1 8 | }) 9 | } 10 | } 11 | 12 | export function reduceCount (): Function { 13 | return (dispatch: Function) => { 14 | dispatch({ 15 | type: types.REDUCE_COUNT, 16 | data: 1 17 | }) 18 | } 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/store/redux/reducers/home.js: -------------------------------------------------------------------------------- 1 | import { 2 | combineReducers 3 | } from 'redux' 4 | 5 | import * as types from '@store/mutation-types' 6 | 7 | export function count (state = 0, action) { 8 | switch (action.type) { 9 | case types.ADD_COUNT: 10 | return state + action.data 11 | case types.REDUCE_COUNT: 12 | return state - action.data 13 | default: 14 | return state 15 | } 16 | } 17 | 18 | export default combineReducers({ 19 | count 20 | }) 21 | -------------------------------------------------------------------------------- /src/app.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | {{#if useRouter}} 3 | import { 4 | BrowserRouter 5 | } from 'react-router-dom' 6 | import RoutesProvider from '@router/index' 7 | 8 | const App = () => { 9 | return ( 10 | 11 | 12 | 13 | ) 14 | } 15 | {{/if}} 16 | {{#unless useRouter}} 17 | import Home from '@pages/Home' 18 | 19 | const App = () => { 20 | return ( 21 | 22 | ) 23 | } 24 | {{/unless}} 25 | 26 | export default App 27 | -------------------------------------------------------------------------------- /src/app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | {{#if useRouter}} 3 | import { 4 | BrowserRouter, 5 | } from 'react-router-dom' 6 | import RoutesProvider from '@router/index' 7 | 8 | const App = () => { 9 | return ( 10 | 11 | 12 | 13 | ) 14 | } 15 | {{/if}} 16 | {{#unless useRouter}} 17 | import Home from '@pages/Home' 18 | 19 | const App = () => { 20 | return ( 21 | 22 | ) 23 | } 24 | {{/unless}} 25 | 26 | export default App 27 | -------------------------------------------------------------------------------- /src/store/redux/reducers/home.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineReducers 3 | } from 'redux' 4 | 5 | import * as types from '@store/mutation-types' 6 | 7 | import { 8 | IActionProps 9 | } from '@store/types' 10 | 11 | export function count (state: number = 0, action: IActionProps): number { 12 | switch (action.type) { 13 | case types.ADD_COUNT: 14 | return state + action.data 15 | case types.REDUCE_COUNT: 16 | return state - action.data 17 | default: 18 | return state 19 | } 20 | } 21 | 22 | export default combineReducers({ 23 | count 24 | }) 25 | -------------------------------------------------------------------------------- /src/components/Hello/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect 3 | } from 'react' 4 | 5 | import classNames from 'classnames' 6 | {{#equal useStyle 'less'}} 7 | import './hello.less' 8 | {{/equal}} 9 | {{#equal useStyle 'scss'}} 10 | import './hello.scss' 11 | {{/equal}} 12 | 13 | import { 14 | PROJECT_NAME 15 | } from '@constance/index' 16 | 17 | const Hello = () => { 18 | const classString = classNames({ 19 | [`${PROJECT_NAME}-comp-hello`]: true 20 | }) 21 | 22 | useEffect(() => { 23 | console.log('this is Hello components') 24 | }, []) 25 | 26 | return ( 27 |
Hello Tiga
28 | ) 29 | } 30 | 31 | export default Hello 32 | -------------------------------------------------------------------------------- /src/components/Hello/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect 3 | } from 'react' 4 | 5 | import classNames from 'classnames' 6 | {{#equal useStyle 'less'}} 7 | import './hello.less' 8 | {{/equal}} 9 | {{#equal useStyle 'scss'}} 10 | import './hello.scss' 11 | {{/equal}} 12 | 13 | import { 14 | PROJECT_NAME 15 | } from '@constance/index' 16 | 17 | interface IHelloProps {} 18 | 19 | const Hello: React.FC = () => { 20 | const classString = classNames({ 21 | [`${PROJECT_NAME}-comp-hello`]: true 22 | }) 23 | 24 | useEffect(() => { 25 | console.log('this is Hello components') 26 | }, []) 27 | 28 | return ( 29 |
Hello Tiga
30 | ) 31 | } 32 | 33 | export default Hello 34 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(false) 3 | 4 | const presets = [ 5 | [ 6 | "@babel/preset-env", { 7 | modules: false 8 | } 9 | ], 10 | '@babel/preset-react', 11 | {{#if useTypeScript}} 12 | '@babel/preset-typescript' 13 | {{/if}} 14 | ] 15 | const plugins = [ 16 | {{#equal useStore 'mobx'}} 17 | [ 18 | '@babel/plugin-proposal-decorators', { 19 | legacy: true 20 | } 21 | ], 22 | [ 23 | '@babel/plugin-proposal-class-properties', { 24 | loose : true 25 | } 26 | ], 27 | {{/equal}} 28 | '@babel/plugin-syntax-dynamic-import' 29 | ] 30 | 31 | return { 32 | presets, 33 | plugins 34 | } 35 | } -------------------------------------------------------------------------------- /src/router/map.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Loadable from 'react-loadable'; 3 | import Loading from '../components/Loading'; 4 | 5 | const Home = Loadable({ 6 | loader: () => import('@pages/Home'), 7 | loading: Loading 8 | }) 9 | 10 | export interface RoutesLists { 11 | name: string; 12 | path?: string; 13 | redirect?: boolean; 14 | component?: React.ReactNode | any; 15 | children?: Array; 16 | meta?: { 17 | title: string; // 用于切换页面title 18 | pageId?: string; // 用于埋点的pageId 19 | } 20 | } 21 | 22 | const routes: Array = [{ 23 | name: 'home', 24 | path: '/home', 25 | component: Home, 26 | meta: { 27 | title: '首页' 28 | } 29 | }, { 30 | name: 'home', 31 | redirect: true 32 | }]; 33 | 34 | export default routes; 35 | -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import '@styles/reset.css' 4 | 5 | {{#equal useStore 'redux'}} 6 | import { Provider } from 'react-redux'; 7 | import store from '@store/index'; 8 | {{/equal}} 9 | {{#equal useStore 'mobx'}} 10 | import store from '@store/index' 11 | import { 12 | context 13 | } from '@store/context' 14 | {{/equal}} 15 | import App from './app' 16 | 17 | {{#equal useStore 'redux'}} 18 | ReactDOM.render( 19 | 20 | 21 | , 22 | document.getElementById('root') 23 | ) 24 | {{/equal}} 25 | {{#equal useStore 'mobx'}} 26 | ReactDOM.render( 27 | 28 | 29 | , 30 | document.getElementById('root') 31 | ) 32 | {{/equal}} 33 | {{#equal useStore 'none'}} 34 | ReactDOM.render( 35 | , 36 | document.getElementById('root') 37 | ) 38 | {{/equal}} -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import '@styles/reset.css' 4 | 5 | {{#equal useStore 'redux'}} 6 | import { Provider } from 'react-redux'; 7 | import store from '@store/index'; 8 | {{/equal}} 9 | {{#equal useStore 'mobx'}} 10 | import store from '@store/index' 11 | import { 12 | context 13 | } from '@store/context' 14 | {{/equal}} 15 | {{#if useRouter}} 16 | import App from './app' 17 | {{/if}} 18 | {{#unless useRouter}} 19 | import App from '@pages/Home' 20 | {{/unless}} 21 | 22 | {{#equal useStore 'mobx'}} 23 | ReactDOM.render( 24 | 25 | 26 | , 27 | document.getElementById('root') 28 | ) 29 | {{/equal}} 30 | {{#equal useStore 'redux'}} 31 | ReactDOM.render( 32 | 33 | 34 | , 35 | document.getElementById('root') 36 | ) 37 | {{/equal}} 38 | {{#equal useStore 'none'}} 39 | ReactDOM.render( 40 | , 41 | document.getElementById('root') 42 | ) 43 | {{/equal}} -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | "type-enum": [ 5 | 2, 6 | 'always', 7 | [ 8 | "build", // 项目构建 9 | "docs", // Adds or alters documentation. 仅仅修改了文档,比如README, CHANGELOG, CONTRIBUTE等等 10 | "chore", // Other changes that don't modify src or test files. 改变构建流程、或者增加依赖库、工具等 11 | "feat", // Adds a new feature. 新增feature 12 | "fix", // Solves a bug. 修复bug 13 | "merge", // Merge branch ? of ?. 14 | "perf", // Improves performance. 优化相关,比如提升性能、体验 15 | "refactor", // Rewrites code without feature, performance or bug changes. 代码重构,没有加新功能或者修复bug 16 | "revert", // Reverts a previous commit. 回滚到上一个版本 17 | "style", // Improves formatting, white-space. 仅仅修改了空格、格式缩进、都好等等,不改变代码逻辑 18 | "test" // Adds or modifies tests. 测试用例,包括单元测试、集成测试等 19 | ] 20 | ], 21 | 'subject-max-length': [2, 'always', 100] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/router/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import rs from './map'; 3 | 4 | import { Switch, Route, HashRouter as Router, Redirect } from 'react-router-dom'; 5 | import { DEFAULT_TITLE } from '@constance/index'; 6 | 7 | const RenderRouters = (route) => { 8 | const redirectPath = route.path ? route.path : rs.filter(item => item.name == route.name)[0].path || '/' 9 | 10 | return ( 11 | route.redirect ? ( 12 | 13 | ) : ( 14 | ( 17 | 18 | )}> 19 | ) 20 | ); 21 | }; 22 | 23 | const RouteProvider = () => { 24 | return ( 25 | 26 | 27 | { 28 | rs.map((route) => ( 29 | RenderRouters(route) 30 | )) 31 | } 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default RouteProvider; 38 | -------------------------------------------------------------------------------- /src/router/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import rs, { 3 | RoutesLists 4 | } from './map'; 5 | 6 | import { Switch, Route, HashRouter as Router, Redirect } from 'react-router-dom'; 7 | import { DEFAULT_TITLE } from '@constance/index'; 8 | 9 | const RenderRouters = (route: RoutesLists) => { 10 | const redirectPath = route.path ? route.path : rs.filter(item => item.name == route.name)[0].path || '/' 11 | 12 | return ( 13 | route.redirect ? ( 14 | 15 | ) : ( 16 | ( 19 | 20 | )}> 21 | ) 22 | ); 23 | }; 24 | 25 | const RouteProvider = () => { 26 | return ( 27 | 28 | 29 | { 30 | rs.map((route: RoutesLists) => ( 31 | RenderRouters(route) 32 | )) 33 | } 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default RouteProvider; 40 | -------------------------------------------------------------------------------- /config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const path = require('path'); 4 | const webpackPromptPlugin = require('webpack-prompt-plugin') 5 | 6 | const resolve = function (dir) { 7 | return path.resolve(__dirname, dir); 8 | } 9 | 10 | module.exports = merge(common, { 11 | mode: 'development', 12 | entry: { 13 | {{#if useTypeScript}} 14 | app: './src/index.tsx' 15 | {{/if}} 16 | {{#unless useTypeScript}} 17 | app: './src/index.jsx' 18 | {{/unless}} 19 | }, 20 | output: { 21 | path: resolve('dist'), 22 | publicPath: '/', 23 | filename: 'js/[name]-[hash].js' 24 | }, 25 | 26 | module: { 27 | rules: [ 28 | ] 29 | }, 30 | 31 | plugins: [ 32 | new webpackPromptPlugin() 33 | ], 34 | 35 | devServer: { 36 | // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。通过传入以下启用: 37 | // contentBase: "./", 38 | host: '0.0.0.0', 39 | // 端口号 40 | port: 1994, 41 | //当有编译器错误或警告时,在浏览器中显示全屏覆盖。默认禁用。如果您只想显示编译器错误: 42 | noInfo: true, 43 | // 配置端口号 44 | overlay: true, 45 | historyApiFallback: true 46 | } 47 | }) 48 | -------------------------------------------------------------------------------- /templates.ignore: -------------------------------------------------------------------------------- 1 | {{#if useTypeScript}} 2 | src/**/*.js 3 | src/**/*.jsx 4 | test/**/*.js 5 | test/**/*.jsx 6 | {{/if}} 7 | {{#unless useTypeScript}} 8 | tsconfig.json 9 | src/**/*.ts 10 | src/**/*.tsx 11 | test/**/*.ts 12 | test/**/*.tsx 13 | {{/unless}} 14 | 15 | {{#unless useRouter}} 16 | src/router/* 17 | {{/unless}} 18 | 19 | {{#equal useStore 'redux'}} 20 | src/store/redux/**/* 21 | src/store/mobx/**/* 22 | {{/equal}} 23 | {{#equal useStore 'mobx'}} 24 | src/store/redux/**/* 25 | src/store/mobx/**/* 26 | {{/equal}} 27 | {{#equal useStore 'none'}} 28 | src/store/**/* 29 | {{/equal}} 30 | 31 | {{#if useTest}} 32 | {{#if useTypeScript}} 33 | .mocharc.yaml 34 | {{/if}} 35 | {{#unless useTypeScript}} 36 | .mocharc.json 37 | {{/unless}} 38 | {{/if}} 39 | 40 | {{#unless useTest}} 41 | test/**/* 42 | .mocharc.yaml 43 | .mocharc.json 44 | {{/unless}} 45 | 46 | {{#equal useStyle 'less'}} 47 | src/**/*.scss 48 | {{/equal}} 49 | {{#equal useStyle 'scss'}} 50 | src/**/*.less 51 | {{/equal}} 52 | {{#equal useStyle 'none'}} 53 | src/**/*.scss 54 | src/**/*.less 55 | {{/equal}} 56 | 57 | {{#unless useGitHook}} 58 | commitlint.config.js 59 | {{/unless}} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "es5", 5 | "lib": [ 6 | "dom", 7 | "dom.iterable", 8 | "esnext" 9 | ], 10 | "allowJs": true, 11 | "noImplicitAny": true, 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "allowSyntheticDefaultImports": true, 15 | "strict": true, 16 | "experimentalDecorators": true, 17 | "forceConsistentCasingInFileNames": true, 18 | {{#if useTest}} 19 | "module": "commonjs", 20 | {{/if}} 21 | {{#unless useTest}} 22 | "module": "esnext", 23 | {{/unless}} 24 | "moduleResolution": "node", 25 | "resolveJsonModule": true, 26 | "isolatedModules": false, 27 | "noEmit": false, 28 | "jsx": "react", 29 | "typeRoots": [ 30 | "node_modules/@types" 31 | ], 32 | "paths": { 33 | "@api/*": ["src/api/*"], 34 | "@assets/*": ["src/assets/*"], 35 | "@components/*": ["src/components/*"], 36 | "@constance/*": ["src/constance/*"], 37 | "@store/*": ["src/store/*"], 38 | "@styles/*": ["src/styles/*"], 39 | "@pages/*": ["src/pages/*"], 40 | "@utils/*": ["src/utils/*"], 41 | "@router/*": ["src/router/*"], 42 | } 43 | }, 44 | "include": [ 45 | "src/**/*", 46 | "global.d.ts" 47 | ] 48 | } -------------------------------------------------------------------------------- /src/pages/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | {{#equal useStore 'redux'}} 4 | import { 5 | connect 6 | } from 'react-redux' 7 | import HomeAction from '@store/actions' 8 | {{/equal}} 9 | {{#equal useStore 'mobx'}} 10 | import { 11 | observer 12 | } from 'mobx-react' 13 | import { 14 | useStore 15 | } from '@store/context' 16 | {{/equal}} 17 | import Hello from '@components/Hello' 18 | {{#equal useStyle 'less'}} 19 | import './home.less' 20 | {{/equal}} 21 | {{#equal useStyle 'scss'}} 22 | import './home.scss' 23 | {{/equal}} 24 | 25 | {{#equal useStore 'none'}} 26 | const Home = (props) => { 27 | return ( 28 |
29 |
this is home
30 | 31 |
32 | ) 33 | } 34 | {{/equal}} 35 | {{#equal useStore 'redux'}} 36 | const Home = (props) => { 37 | return ( 38 |
39 |
this is home
40 | 41 | {props.count} 42 |
+ 1
43 |
- 1
44 |
45 | ) 46 | } 47 | {{/equal}} 48 | {{#equal useStore 'mobx'}} 49 | const Home = observer((props) => { 50 | const { homeStore } = useStore() 51 | return ( 52 |
53 |
this is home
54 | 55 | { homeStore.count } 56 |
homeStore.addCount()}> + 1
57 |
homeStore.reduceCount()}> - 1
58 |
59 | ) 60 | }) 61 | {{/equal}} 62 | 63 | {{#equal useStore 'redux'}} 64 | export default connect( 65 | ({home}) => home, 66 | HomeAction 67 | )(Home) 68 | {{/equal}} 69 | {{#unEqual useStore 'redux'}} 70 | export default Home 71 | {{/unEqual}} 72 | -------------------------------------------------------------------------------- /src/pages/Home/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | {{#equal useStore 'redux'}} 4 | import { 5 | connect 6 | } from 'react-redux' 7 | import HomeAction from '@store/actions' 8 | {{/equal}} 9 | {{#equal useStore 'mobx'}} 10 | import { 11 | observer 12 | } from 'mobx-react' 13 | import { 14 | useStore 15 | } from '@store/context' 16 | {{/equal}} 17 | 18 | import Hello from '@components/Hello' 19 | {{#equal useStyle 'less'}} 20 | import './home.less' 21 | {{/equal}} 22 | {{#equal useStyle 'scss'}} 23 | import './home.scss' 24 | {{/equal}} 25 | 26 | 27 | {{#equal useStore 'none'}} 28 | interface IHomeProps {} 29 | 30 | const Home: React.FC = (props) => { 31 | return ( 32 |
33 |
this is home
34 | 35 |
36 | ) 37 | } 38 | {{/equal}} 39 | {{#equal useStore 'redux'}} 40 | 41 | interface IHomeProps { 42 | count: number 43 | addCount: () => void 44 | reduceCount: () => void 45 | } 46 | const Home: React.FC> = (props) => { 47 | return ( 48 |
49 |
this is home
50 | 51 | {props.count} 52 |
+ 1
53 |
- 1
54 |
55 | ) 56 | } 57 | {{/equal}} 58 | {{#equal useStore 'mobx'}} 59 | 60 | interface IHomeProps { 61 | count: number 62 | addCount: () => void 63 | reduceCount: () => void 64 | } 65 | const Home: React.FC> = observer((props) => { 66 | const { homeStore } = useStore() 67 | return ( 68 |
69 |
this is home
70 | 71 | { homeStore.count } 72 |
homeStore.addCount()}> + 1
73 |
homeStore.reduceCount()}> - 1
74 |
75 | ) 76 | }) 77 | {{/equal}} 78 | 79 | {{#equal useStore 'redux'}} 80 | export default connect( 81 | (state: any) => state.home, 82 | HomeAction 83 | )(Home) 84 | {{/equal}} 85 | {{#unEqual useStore 'redux'}} 86 | export default Home 87 | {{/unEqual}} 88 | -------------------------------------------------------------------------------- /config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const path = require('path'); 3 | const TerserPlugin = require('terser-webpack-plugin'); 4 | const common = require('./webpack.common.js'); 5 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 6 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 7 | 8 | // css压缩打包相关 9 | var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 10 | 11 | // 打包清除dist目录 12 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 13 | 14 | module.exports = merge(common, { 15 | mode: 'production', 16 | entry: { 17 | {{#if useTypeScript}} 18 | app: './src/index.tsx', 19 | {{/if}} 20 | {{#unless useTypeScript}} 21 | app: './src/index.jsx', 22 | {{/unless}} 23 | }, 24 | externals: { 25 | // 使用 externals 需要在 index.html 中配置需要的 库 的cdn地址 26 | react: 'React', 27 | {{#if useRouter}} 28 | 'react-dom': 'ReactDOM', 29 | {{/if}} 30 | {{#equal useStore 'mobx'}} 31 | 'mobx': 'mobx' 32 | {{/equal}} 33 | }, 34 | output: { 35 | path: path.resolve(__dirname, './../dist'), 36 | publicPath: './', 37 | filename: 'js/[name]-[hash].js', 38 | libraryTarget: 'umd' 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.js$/, 44 | use: { 45 | loader: 'babel-loader', 46 | } 47 | }, 48 | ] 49 | }, 50 | plugins: [ 51 | // 清除 52 | new CleanWebpackPlugin({ 53 | cleanOnceBeforeBuildPatterns: path.resolve(__dirname, 'dist') 54 | }), 55 | 56 | // css 压缩 57 | new OptimizeCssAssetsPlugin({}), 58 | 59 | new BundleAnalyzerPlugin() 60 | ], 61 | optimization: { 62 | namedModules: true, 63 | minimizer: [ 64 | new TerserPlugin({ 65 | cache: true, 66 | parallel: true, 67 | sourceMap: true, // Must be set to true if using source-maps in production 68 | terserOptions: { 69 | // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions 70 | } 71 | }), 72 | ], 73 | splitChunks: { 74 | chunks: "all", 75 | minSize: 30000, 76 | minChunks: 3, 77 | maxAsyncRequests: 5, 78 | maxInitialRequests: 3, 79 | name: true, 80 | cacheGroups: { 81 | default: { 82 | minChunks: 2, 83 | priority: -20, 84 | reuseExistingChunk: true, 85 | }, 86 | vendors: { 87 | test: /[\\/]node_modules[\\/]/, 88 | chunks: "initial", 89 | name: "vendor", 90 | priority: 10, 91 | enforce: true, 92 | }, 93 | commons: { 94 | name: 'vendors', 95 | chunks: 'all', 96 | minChunks: 2, 97 | maxInitialRequests: 5, // The default limit is too small to showcase the effect 98 | minSize: 0 // This is example is too small to create commons chunks 99 | } 100 | } 101 | }, 102 | runtimeChunk: "single", 103 | minimizer: [ 104 | new UglifyJsPlugin({ 105 | test: /\.js(\?.*)?$/i 106 | }), 107 | ] 108 | } 109 | }); -------------------------------------------------------------------------------- /config/webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 5 | 6 | const resolve = (dir) => { 7 | return path.resolve(__dirname, dir) 8 | } 9 | 10 | const devMode = process.env.NODE_ENV === "development" 11 | 12 | module.exports = { 13 | plugins: [ 14 | new HtmlWebpackPlugin({ 15 | filename: 'index.html', 16 | template: 'index.html', 17 | inject: true, 18 | title: "{{name}}", 19 | favicon: 'src/assets/favicon.ico', 20 | minify: { 21 | removeComments: true 22 | } 23 | }), 24 | new MiniCssExtractPlugin ({ 25 | filename: "css/[name]-[hash].css", 26 | chunkFilename: "css/[name]-[hash].css" 27 | }), 28 | ], 29 | 30 | module: { 31 | rules: [ 32 | { 33 | {{#if useTypeScript}} 34 | test: /\.(js|jsx|ts|tsx)$/, 35 | {{/if}} 36 | {{#unless useTypeScript}} 37 | test: /\.(js|jsx)$/, 38 | {{/unless}} 39 | loader: 'babel-loader', 40 | query: { 41 | compact: false 42 | } 43 | }, 44 | { 45 | test: /\.(c)ss$/, 46 | use: [ 47 | devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 48 | { 49 | loader: 'css-loader', 50 | options: { 51 | modules:true 52 | } 53 | }, 54 | { 55 | loader:"postcss-loader", 56 | options: { 57 | plugins: () => [ 58 | require('autoprefixer')() 59 | ] 60 | } 61 | }, 62 | ] 63 | }, 64 | {{#equal useStyle 'less'}} 65 | { 66 | test: /\.less$/, 67 | use: [ 68 | devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 69 | "css-loader", 70 | "less-loader", 71 | { 72 | loader: 'style-resources-loader', 73 | options: { 74 | patterns: path.resolve(__dirname, './../src/styles/val.less') 75 | } 76 | } 77 | ], 78 | }, 79 | {{/equal}} 80 | {{#equal useStyle 'scss'}} 81 | { 82 | test: /\.(sc|sa)ss$/, 83 | use: [ 84 | devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 85 | "css-loader", 86 | "sass-loader", 87 | { 88 | loader: 'style-resources-loader', 89 | options: { 90 | patterns: path.resolve(__dirname, './../src/styles/val.scss') 91 | } 92 | } 93 | ], 94 | }, 95 | {{/equal}} 96 | { 97 | test: /\.(ttf|eot|woff|woff2)$/, 98 | use: [ 99 | { 100 | loader: 'url-loader' 101 | } 102 | ] 103 | }, 104 | { 105 | test: /\.(png|jpg|gif)$/, 106 | use: [ 107 | { 108 | loader: 'url-loader', 109 | options: { 110 | limit: 8192 111 | } 112 | } 113 | ] 114 | } 115 | ] 116 | }, 117 | 118 | resolve: { 119 | alias: { 120 | '@api': resolve('./../src/api'), 121 | '@assets': resolve('./../src/assets'), 122 | '@components': resolve('./../src/components'), 123 | '@constance': resolve('./../src/constance'), 124 | '@store': resolve('./../src/store'), 125 | '@styles': resolve('./../src/styles'), 126 | '@pages': resolve('./../src/pages'), 127 | '@utils': resolve('./../src/utils'), 128 | '@router': resolve('./../src/router') 129 | }, 130 | extensions: ['.tsx', '.ts', '.jsx', '.js'] 131 | }, 132 | } 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{name}}", 3 | "version": "1.0.0", 4 | "description": "{{description}}", 5 | "author": "{{author}}", 6 | "main": "index.js", 7 | "license": "ISC", 8 | "scripts": { 9 | {{#if useTest}} 10 | "mocha": "mocha", 11 | {{/if}} 12 | "dev": "webpack-dev-server --config ./config/webpack.dev.js --progress", 13 | "build": "webpack --progress --config ./config/webpack.prod.js" 14 | }, 15 | {{#if useGitHook}} 16 | "husky": { 17 | "hooks": { 18 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 19 | } 20 | }, 21 | {{/if}} 22 | "dependencies": { 23 | "react": "^16.12.0", 24 | "react-dom": "^16.12.0" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.8.3", 28 | "@babel/preset-env": "^7.8.3", 29 | "@babel/preset-react": "^7.8.3", 30 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 31 | {{#unless useTypeScript}} 32 | {{#equal useStore 'mobx'}} 33 | "@babel/plugin-proposal-decorators": "^7.8.3", 34 | "@babel/plugin-proposal-class-properties": "^7.8.3", 35 | {{/equal}} 36 | {{#if useTest}} 37 | "@babel/register": "^7.8.3", 38 | {{/if}} 39 | {{/unless}} 40 | {{#if useGitHook}} 41 | "@commitlint/cli": "^8.3.5", 42 | "@commitlint/config-conventional": "^8.3.4", 43 | {{/if}} 44 | {{#if useTypeScript}} 45 | "@babel/preset-typescript": "^7.9.0", 46 | {{#if useTest}} 47 | "@types/chai": "^4.2.8", 48 | "@types/mocha": "^7.0.1", 49 | "ts-node": "^8.6.2", 50 | {{/if}} 51 | "@types/classnames": "^2.2.9", 52 | "@types/react": "^16.9.17", 53 | "@types/react-dom": "^16.9.5", 54 | {{#equal useStore 'redux'}} 55 | "@types/react-redux": "^7.1.6", 56 | {{/equal}} 57 | {{#if useRouter}} 58 | "@types/react-loadable": "^5.5.3", 59 | "@types/react-router-dom": "^5.1.3", 60 | {{/if}} 61 | {{/if}} 62 | "autoprefixer": "^9.7.4", 63 | "babel-loader": "^8.0.6", 64 | "css-loader": "^3.4.2", 65 | "classnames": "^2.2.6", 66 | "clean-webpack-plugin": "^3.0.0", 67 | "html-webpack-plugin": "^3.2.0", 68 | {{#if useGitHook}} 69 | "husky": "^4.2.3", 70 | {{/if}} 71 | {{#equal useStyle 'scss'}} 72 | "node-sass": "^4.13.1", 73 | {{/equal}} 74 | "mini-css-extract-plugin": "^0.9.0", 75 | {{#equal useStore 'mobx'}} 76 | "mobx": "^5.15.2", 77 | "mobx-react": "^6.1.5", 78 | {{/equal}} 79 | {{#if useTest}} 80 | "mocha": "^7.0.1", 81 | "chai": "^4.2.0", 82 | {{/if}} 83 | {{#equal useStyle 'less'}} 84 | "less": "^3.10.3", 85 | "less-loader": "^5.0.0", 86 | {{/equal}} 87 | "optimize-css-assets-webpack-plugin": "^5.0.3", 88 | "postcss-loader": "^3.0.0", 89 | {{#if useRouter}} 90 | "react-loadable": "^5.5.0", 91 | "react-router-dom": "^5.1.2", 92 | {{/if}} 93 | {{#equal useStore 'redux'}} 94 | "react-redux": "^7.1.3", 95 | "redux": "^4.0.5", 96 | "redux-thunk": "^2.3.0", 97 | {{/equal}} 98 | {{#equal useStyle 'scss'}} 99 | "sass-loader": "^8.0.2", 100 | {{/equal}} 101 | "style-loader": "^1.1.2", 102 | {{#unEqual useStyle 'none'}} 103 | "style-resources-loader": "^1.3.3", 104 | {{/unEqual}} 105 | "terser-webpack-plugin": "^2.3.2", 106 | {{#if useTypeScript}} 107 | "ts-loader": "^6.2.1", 108 | "typescript": "^3.7.5", 109 | {{/if}} 110 | "uglifyjs-webpack-plugin": "^2.2.0", 111 | "url-loader": "^3.0.0", 112 | "webpack": "^4.41.5", 113 | "webpack-bundle-analyzer": "^3.6.0", 114 | "webpack-cli": "^3.3.10", 115 | "webpack-dev-server": "^3.10.1", 116 | "webpack-merge": "^4.2.2", 117 | "webpack-prompt-plugin": "^1.1.2" 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/styles/reset.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /** 4 | * 1. Change the default font family in all browsers (opinionated). 5 | * 2. Correct the line height in all browsers. 6 | * 3. Prevent adjustments of font size after orientation changes in 7 | * IE on Windows Phone and in iOS. 8 | */ 9 | 10 | /* Document 11 | ========================================================================== */ 12 | 13 | html { 14 | font-family: sans-serif; /* 1 */ 15 | line-height: 1.15; /* 2 */ 16 | -ms-text-size-adjust: 100%; /* 3 */ 17 | -webkit-text-size-adjust: 100%; /* 3 */ 18 | } 19 | 20 | /* Sections 21 | ========================================================================== */ 22 | 23 | /** 24 | * Remove the margin in all browsers (opinionated). 25 | */ 26 | 27 | body { 28 | margin: 0; 29 | } 30 | 31 | /** 32 | * Add the correct display in IE 9-. 33 | */ 34 | 35 | article, 36 | aside, 37 | footer, 38 | header, 39 | nav, 40 | section { 41 | display: block; 42 | } 43 | 44 | /** 45 | * Correct the font size and margin on `h1` elements within `section` and 46 | * `article` contexts in Chrome, Firefox, and Safari. 47 | */ 48 | 49 | h1 { 50 | font-size: 2em; 51 | margin: 0.67em 0; 52 | } 53 | 54 | /* Grouping content 55 | ========================================================================== */ 56 | 57 | /** 58 | * Add the correct display in IE 9-. 59 | * 1. Add the correct display in IE. 60 | */ 61 | 62 | figcaption, 63 | figure, 64 | main { /* 1 */ 65 | display: block; 66 | } 67 | 68 | /** 69 | * Add the correct margin in IE 8. 70 | */ 71 | 72 | figure { 73 | margin: 1em 40px; 74 | } 75 | 76 | /** 77 | * 1. Add the correct box sizing in Firefox. 78 | * 2. Show the overflow in Edge and IE. 79 | */ 80 | 81 | hr { 82 | box-sizing: content-box; /* 1 */ 83 | height: 0; /* 1 */ 84 | overflow: visible; /* 2 */ 85 | } 86 | 87 | /** 88 | * 1. Correct the inheritance and scaling of font size in all browsers. 89 | * 2. Correct the odd `em` font sizing in all browsers. 90 | */ 91 | 92 | pre { 93 | font-family: monospace, monospace; /* 1 */ 94 | font-size: 1em; /* 2 */ 95 | } 96 | 97 | /* Text-level semantics 98 | ========================================================================== */ 99 | 100 | /** 101 | * 1. Remove the gray background on active links in IE 10. 102 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 103 | */ 104 | 105 | a { 106 | background-color: transparent; /* 1 */ 107 | -webkit-text-decoration-skip: objects; /* 2 */ 108 | } 109 | 110 | /** 111 | * Remove the outline on focused links when they are also active or hovered 112 | * in all browsers (opinionated). 113 | */ 114 | 115 | a:active, 116 | a:hover { 117 | outline-width: 0; 118 | } 119 | 120 | /** 121 | * 1. Remove the bottom border in Firefox 39-. 122 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 123 | */ 124 | 125 | abbr[title] { 126 | border-bottom: none; /* 1 */ 127 | text-decoration: underline; /* 2 */ 128 | text-decoration: underline dotted; /* 2 */ 129 | } 130 | 131 | /** 132 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 133 | */ 134 | 135 | b, 136 | strong { 137 | font-weight: inherit; 138 | } 139 | 140 | /** 141 | * Add the correct font weight in Chrome, Edge, and Safari. 142 | */ 143 | 144 | b, 145 | strong { 146 | font-weight: bolder; 147 | } 148 | 149 | /** 150 | * 1. Correct the inheritance and scaling of font size in all browsers. 151 | * 2. Correct the odd `em` font sizing in all browsers. 152 | */ 153 | 154 | code, 155 | kbd, 156 | samp { 157 | font-family: monospace, monospace; /* 1 */ 158 | font-size: 1em; /* 2 */ 159 | } 160 | 161 | /** 162 | * Add the correct font style in Android 4.3-. 163 | */ 164 | 165 | dfn { 166 | font-style: italic; 167 | } 168 | 169 | /** 170 | * Add the correct background and color in IE 9-. 171 | */ 172 | 173 | mark { 174 | background-color: #ff0; 175 | color: #000; 176 | } 177 | 178 | /** 179 | * Add the correct font size in all browsers. 180 | */ 181 | 182 | small { 183 | font-size: 80%; 184 | } 185 | 186 | /** 187 | * Prevent `sub` and `sup` elements from affecting the line height in 188 | * all browsers. 189 | */ 190 | 191 | sub, 192 | sup { 193 | font-size: 75%; 194 | line-height: 0; 195 | position: relative; 196 | vertical-align: baseline; 197 | } 198 | 199 | sub { 200 | bottom: -0.25em; 201 | } 202 | 203 | sup { 204 | top: -0.5em; 205 | } 206 | 207 | /* Embedded content 208 | ========================================================================== */ 209 | 210 | /** 211 | * Add the correct display in IE 9-. 212 | */ 213 | 214 | audio, 215 | video { 216 | display: inline-block; 217 | } 218 | 219 | /** 220 | * Add the correct display in iOS 4-7. 221 | */ 222 | 223 | audio:not([controls]) { 224 | display: none; 225 | height: 0; 226 | } 227 | 228 | /** 229 | * Remove the border on images inside links in IE 10-. 230 | */ 231 | 232 | img { 233 | border-style: none; 234 | } 235 | 236 | /** 237 | * Hide the overflow in IE. 238 | */ 239 | 240 | svg:not(:root) { 241 | overflow: hidden; 242 | } 243 | 244 | /* Forms 245 | ========================================================================== */ 246 | 247 | /** 248 | * 1. Change the font styles in all browsers (opinionated). 249 | * 2. Remove the margin in Firefox and Safari. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | font-family: sans-serif; /* 1 */ 258 | font-size: 100%; /* 1 */ 259 | line-height: 1.15; /* 1 */ 260 | margin: 0; /* 2 */ 261 | } 262 | 263 | /** 264 | * Show the overflow in IE. 265 | * 1. Show the overflow in Edge. 266 | */ 267 | 268 | button, 269 | input { /* 1 */ 270 | overflow: visible; 271 | } 272 | 273 | /** 274 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 275 | * 1. Remove the inheritance of text transform in Firefox. 276 | */ 277 | 278 | button, 279 | select { /* 1 */ 280 | text-transform: none; 281 | } 282 | 283 | /** 284 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 285 | * controls in Android 4. 286 | * 2. Correct the inability to style clickable types in iOS and Safari. 287 | */ 288 | 289 | button, 290 | html [type="button"], /* 1 */ 291 | [type="reset"], 292 | [type="submit"] { 293 | -webkit-appearance: button; /* 2 */ 294 | } 295 | 296 | /** 297 | * Remove the inner border and padding in Firefox. 298 | */ 299 | 300 | button::-moz-focus-inner, 301 | [type="button"]::-moz-focus-inner, 302 | [type="reset"]::-moz-focus-inner, 303 | [type="submit"]::-moz-focus-inner { 304 | border-style: none; 305 | padding: 0; 306 | } 307 | 308 | /** 309 | * Restore the focus styles unset by the previous rule. 310 | */ 311 | 312 | button:-moz-focusring, 313 | [type="button"]:-moz-focusring, 314 | [type="reset"]:-moz-focusring, 315 | [type="submit"]:-moz-focusring { 316 | outline: 1px dotted ButtonText; 317 | } 318 | 319 | /** 320 | * Change the border, margin, and padding in all browsers (opinionated). 321 | */ 322 | 323 | fieldset { 324 | border: 1px solid #c0c0c0; 325 | margin: 0 2px; 326 | padding: 0.35em 0.625em 0.75em; 327 | } 328 | 329 | /** 330 | * 1. Correct the text wrapping in Edge and IE. 331 | * 2. Correct the color inheritance from `fieldset` elements in IE. 332 | * 3. Remove the padding so developers are not caught out when they zero out 333 | * `fieldset` elements in all browsers. 334 | */ 335 | 336 | legend { 337 | box-sizing: border-box; /* 1 */ 338 | color: inherit; /* 2 */ 339 | display: table; /* 1 */ 340 | max-width: 100%; /* 1 */ 341 | padding: 0; /* 3 */ 342 | white-space: normal; /* 1 */ 343 | } 344 | 345 | /** 346 | * 1. Add the correct display in IE 9-. 347 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 348 | */ 349 | 350 | progress { 351 | display: inline-block; /* 1 */ 352 | vertical-align: baseline; /* 2 */ 353 | } 354 | 355 | /** 356 | * Remove the default vertical scrollbar in IE. 357 | */ 358 | 359 | textarea { 360 | overflow: auto; 361 | } 362 | 363 | /** 364 | * 1. Add the correct box sizing in IE 10-. 365 | * 2. Remove the padding in IE 10-. 366 | */ 367 | 368 | [type="checkbox"], 369 | [type="radio"] { 370 | box-sizing: border-box; /* 1 */ 371 | padding: 0; /* 2 */ 372 | } 373 | 374 | /** 375 | * Correct the cursor style of increment and decrement buttons in Chrome. 376 | */ 377 | 378 | [type="number"]::-webkit-inner-spin-button, 379 | [type="number"]::-webkit-outer-spin-button { 380 | height: auto; 381 | } 382 | 383 | /** 384 | * 1. Correct the odd appearance in Chrome and Safari. 385 | * 2. Correct the outline style in Safari. 386 | */ 387 | 388 | [type="search"] { 389 | -webkit-appearance: textfield; /* 1 */ 390 | outline-offset: -2px; /* 2 */ 391 | } 392 | 393 | /** 394 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 395 | */ 396 | 397 | [type="search"]::-webkit-search-cancel-button, 398 | [type="search"]::-webkit-search-decoration { 399 | -webkit-appearance: none; 400 | } 401 | 402 | /** 403 | * 1. Correct the inability to style clickable types in iOS and Safari. 404 | * 2. Change font properties to `inherit` in Safari. 405 | */ 406 | 407 | ::-webkit-file-upload-button { 408 | -webkit-appearance: button; /* 1 */ 409 | font: inherit; /* 2 */ 410 | } 411 | 412 | /* Interactive 413 | ========================================================================== */ 414 | 415 | /* 416 | * Add the correct display in IE 9-. 417 | * 1. Add the correct display in Edge, IE, and Firefox. 418 | */ 419 | 420 | details, /* 1 */ 421 | menu { 422 | display: block; 423 | } 424 | 425 | /* 426 | * Add the correct display in all browsers. 427 | */ 428 | 429 | summary { 430 | display: list-item; 431 | } 432 | 433 | /* Scripting 434 | ========================================================================== */ 435 | 436 | /** 437 | * Add the correct display in IE 9-. 438 | */ 439 | 440 | canvas { 441 | display: inline-block; 442 | } 443 | 444 | /** 445 | * Add the correct display in IE. 446 | */ 447 | 448 | template { 449 | display: none; 450 | } 451 | 452 | /* Hidden 453 | ========================================================================== */ 454 | 455 | /** 456 | * Add the correct display in IE 10-. 457 | */ 458 | 459 | [hidden] { 460 | display: none; 461 | } --------------------------------------------------------------------------------