Заглавное изображение: Pixabay
В начале проекта пришло время выходить в онлайн. Во многих местах спецификация кода в основном игнорируется.До конца первого выпуска я оглядываюсь назад на код, написанный ранее, и я не могу смотреть на него прямо. Для того, чтобы облегчить задачу тем, кто возьмет на себя управление в будущем, и упростить отладку для меня в будущем, при запуске некоторых требований второй фазы, при рефакторинге части кода на первой фазе, есть еще какой-то выигрыш.
Стек технологий проекта:
- nodejs
- javascript
- react
- redux
- react-router
- webpack
Предыдущая архитектура была react-router2, которая позже была заменена react-router4. Код выглядит более модульным.
входная модульная
Сам проект представляет собой системную коллекцию, и пользователи будут отображать различную навигацию по меню в соответствии с разными разрешениями. На данный момент есть 3 части:
Каждый модуль имеет отдельное действие, маршрутизатор, редьюсер и сервер.
упаковка фрагмента веб-пакета
entry: {
index: './index.jsx',
1: './1/router/index.jsx',
2: './2/router/index.jsx',
3: './3/router/index.jsx',
vendor: [
'react',
'react-router-dom',
'antd',
'prop-types',
'react-router-redux',
'react-redux',
'redux',
'lodash',
'react-dom',
],
},
маршрутизация
Корневой маршрут просто должен указывать на файл маршрута каждого модуля.
<Route path="/" exact component={IndexComponent} />
{/* xxx路由 start */}
<Route path="/xxx1" component={1Layout} />
{/* xxx路由 start */}
<Route path="/xxx2" component={2Layout} />
{/* xxx路由 start */}
<Route path="/xxx3" component={3Layout} />
Разрешения, переадресация интерфейса
Поскольку серверная часть каждой системы — это не одна и та же группа людей, а развернутые машины не фиксированы, поэтому уровень переадресации интерфейса выполняется с узлом, интерфейсная страница получает доступ к фиксированному адресу, а затем узел используется для доступа. различные фоновые машины. В то же время часть разрешений должна переносить файлы cookie между доменами, что делается вместе с node.
тест, формальный
Это адрес предыдущего различия между онлайн- и офлайн-упаковкой.Поскольку webpack не сделал слишком много настроек, он временно используется для различения среды упаковки таким образом. Но я предпочитаю использовать сценарий оболочки, чтобы различать, может быть удобнее напрямую отлаживать онлайн-интерфейс.
const isLocal = location.host.indexOf('localhost') === 0;
export const serverUrl = !IS_PRODUCTION ? devUrl : isLocal ? devUrl : `//${location.host}`;
перечислить
Значение статического перечисления внешнего интерфейса
На страницах не допускаются следующие слова:
- 1, 2, 3...целый тип
- 'успех', 'неудача', ... и т.д. типы символов
// 静态枚举值及请求API参数
this._private = {
dispatch: props.dispatch,
// 路由方法
history: props.history,
// 当前手机系统
os: '',
...
};
Код ошибки, нормализованное сообщение об ошибке
const errnoToErrmsg = {
unknownError: 1001,
paramLost: 1002,
paramInvalid: 1003,
authFailed: 1006,
signExpired: 1007,
...
}
Значение статуса, стандартизация внешнего бизнес-кода
const xxxStatus = {
toBeAssigned: '待分配',
pending: '待处理',
processing: '处理中',
processed: '已处理',
notDealtWith: '不处理',
description(rawValue) {
switch (rawValue) {
case this.toBeAssigned:
return '1';
case this.pending:
return '2';
case this.processing:
return '3';
case this.processed:
return '4';
case this.notDealtWith:
return '5';
default:
return '';
}
},
};
export { FeedbackStatus };
Внешнее и внутреннее сопоставление полей
Передняя часть — это номенклатура верблюжьего регистра, а задняя часть — подчеркивание «_», поэтому требуется сопоставление, что также более удобно для отладки. Временно используйте следующий глупый метод. Эту часть лучше писать на уровне узла.
export const ToFE = {
errno: 'errno',
errmsg: 'errmsg',
}
export const ToBackup = {
errno: 'errno',
errmsg: 'errmsg',
}
import { ToFE, ToBackup } from '../config/define';
class Tools {
/**
* isObject
* @param {*} data
*/
isObject(data) {
return Object.prototype.toString.call(data) === '[object Object]';
}
/**
* isArray
* @param {*} data
*/
isArray(data) {
return Object.prototype.toString.call(data) === '[object Array]';
}
/**
* field Transfer
* 后端"_"格式字段映射到前端驼峰命名字段
* @param {*} data
* recursion => 递归遍历对象和数组两种类型的数据
*/
fieldTransfer(data) {
// 对象类型
if (this.isObject(data)) {
return this.objectTransfer(data);
}
if (this.isArray(data)) {
return this.arrTransfer(data);
}
return data;
}
// 对象遍历
objectTransfer(data) {
let result = {};
for (const item in data) {
if (this.isObject(data[item])) {
result[ToFE[`${item}`] || item] = this.objectTransfer(data[item]);
continue;
}
if (this.isArray(data[item])) {
result[ToFE[`${item}`] || item] = this.arrTransfer(data[item]);
continue;
}
result[ToFE[`${item}`] || item] = data[item];
}
return result;
}
// 数组遍历
arrTransfer(data) {
let result = [];
for (let i = 0, j = data.length; i < j; i++) {
if (this.isObject(data[i])) {
result[i] = this.objectTransfer(data[i]);
continue;
}
if (this.isArray(data[i])) {
result[i] = this.arrTransfer(data[i]);
continue;
}
result[i] = data[i];
}
return result;
}
// 接口参数对象构建
buildParams(parameters) {
if (!this.isObject(parameters)) {
throw 'parameters must be array object';
}
const params = {};
if (Object.keys(parameters) === 0) {
return params;
}
for (let key in parameters) {
parameters[key] !== '' && (params[ToBackup[key]] = parameters[key]);
}
return params;
}
}
export default new Tools();
Уровень API
В настоящее время параметры tools.buildParams(параметры) все еще запутаны в пути передачи объекта или передачи массива.Достаточно передать аргументы непосредственно передачей массива.Недостаток в том, что параметры передаются в черном ящике, и параметры нельзя быстро оценить и отладить; преимущество в том, что параметры в _fetchxxx не нужно перечислять, просто объект. Обход объекта нужно конструировать самому, минус в том, что нужно повторно прописывать параметры, плюс в том, что он более интуитивно понятен.
/**
* xxx接口
* /xxx/v1/xxx/xxx
* @param {*}
* firstLevel => (可选参数) => xxx
* midLevel => (可选参数) => xxx
* lastLevel => (可选参数) => xxx
* startAt => (可选参数) => xxx
* endAt => (可选参数) => xxx
*/
export const _fetchxxx = ({
firstLevel = '',
midLevel = '',
lastLevel = '',
startAt = '',
endAt = '',
}) => {
const parameters = { firstLevel, midLevel, lastLevel, startAt, endAt };
const params = tools.buildParams(parameters);
return request(`${xxx}xxx/xxx`, {
method: 'post',
body: qs.stringify(params),
}).then(data => tools.fieldTransfer(data));
};
тайник
Унифицированное соглашение об именах кеша для предотвращения конфликтов кеша
class LocalStorage {
set(key, val) {
window.localStorage && localStorage.setItem(key, JSON.stringify(val));
}
get(key) {
return window.localStorage && JSON.parse(localStorage.getItem(key));
}
remove(key) {
window.localStorage && localStorage.removeItem(key);
}
sSet(key, val) {
window.sessionStorage && sessionStorage.setItem(key, JSON.stringify(val));
}
sGet(key) {
return window.sessionStorage && JSON.parse(sessionStorage.getItem(key));
}
sRemove(key) {
window.sessionStorage && sessionStorage.removeItem(key);
}
}
let Storage = new LocalStorage();
Storage.KEYS = {
TOKEN: 'TOKEN',
PV_KEY: 'PV_KEY'
};
Object.freeze && Object.freeze(Storage.KEYS);
export default Storage;
Feature
- Модули загружаются по запросу, а механизм связи между модулями настраивается
- Шаблон регистрации модуля, интерфейсный доступ предоставляет инструменты регистрации, модули развертываются отдельно, динамически регистрируются и независимая CDN. Компиляция выполняется единообразно сервером
- Сам код проекта на стороне сервера предварительно скомпилирован для повышения производительности выполнения и снижения рисков развертывания.
- Результаты компиляции сохраняются единообразно и поддерживают переключение и откат по имени ветки.
Flag
Есть еще много интересных вещей, которые нужно сделать, и каждая оптимизация — это реконструкция самой себя. 2018 бои! ! !