Всего более 9000 слов, и чтение занимает около 10 минут.
напиши первым
Для передней части,github
Это сокровище. Делайте что угодно, вы должны быть профессионалом, вы можете найти много знаний, особенно во фронтенде, впереди вас ждет много хорошего. Хороший исходный код компонентов, хорошие шаблоны проектирования, хорошие тестовые решения и хорошая структура кода — все это в пределах вашей досягаемости, поэтому не думайте, что вы не можете,coding just api
, что вам нужно освоить, так это мышление и мышление программирования.
По сути, эта статья такжеant design
Пасхальные яйца имеют к этому какое-то отношение. Потому что кто-то сказал, кто сказал тебе не читатьnpm
Исходный код пакета, многим может показаться, что чтениеnpm
Исходный код пакета — очень сложная штука, но я хочу вам сказать,npm
Это сокровище с передним концом. Ты сможешьnpm
Правда, увидев много вещей в сумке, вы можете увидеть лучшее в миреnpm
Идеи пакетного программирования.
Например, вы можете увидеть их структуру кода, их зависимости, то, как их код взаимодействует, их спецификации написания кода и так далее. Итак, теперь я передам самую горячую мультитерминальную унифицированную структуру.taro
чтобы показать вам, как анализироватьCLI
Сгенерированоnpm
код пакета. Если статью нельзя проанализировать слишком подробно, я возьму ее в качестве руководства и скажу всем, чтобы она не поддавалась на критику.node_modules
Веревка мешков была напугана, и я не смел смотреть на нее, боясь не понять ее. На самом деле не так непонятно, как вы думаете, вообще известныйnpm
Пакеты, структуры кода очень дружелюбны, и понять их не сложнее, чем читать код ваших коллег (вы понимаете). и чтениеnpm
В процессе бэггинга вас ждет много сюрпризов и много вдохновения. Ты взволнован, ты счастлив, эм, тогда возьми меня за руку, следуй за мной, и я возьму тебя распутатьnpm
Упакуйте эту загадочную и красивую вуаль.
что случилось с таро инит
воплощать в жизньtaro init xxx
Задний,package.json
Зависимости показаны на рисунке ниже
Вы обнаружите, что при инициализацииCLI
Когда установлено много зависимостей, то в это время, если вы перейдете кnode_modules
, будет очень неудобно, т.к. установлено много-много зависимых пакетов, что тоже очень много людейnode_modules
После каталога причина, по которой он закрывается сразу, он может застрять, если он не закрыт. Тогда давайте поиграем немного спокойнее, не делайте так много, мы входим в режим полос, загружаем пакеты один за другим, следуемtaro init
изpackage.json
установки, давайте разберем код пакета.
Проанализируйте @tarojs/components
правильноnode_modules
Сделайте скриншот, картина выглядит следующим образом:
Из картинки мы видим, что установлено много зависимостей, а пакеты, которые имеют непосредственное отношение к нам,@tarojs
,Открытым@tarojs
можно увидеть:
На самом деле вы ничего не найдете, давайте посмотримsrc
Что есть в каталоге:
анализироватьsrc/index.js
документ
index.js
Код файла следующий:
import 'weui'
export { default as View } from './view'
export { default as Block } from './block'
export { default as Image } from './image'
export { default as Text } from './text'
export { default as Switch } from './switch'
export { default as Button } from './button'
// 其他组件省略不写了
Вы обнаружите, что это концентрацияexport
Место для различных компонентов, из кода здесь мы можем понять, почему вtaro
Компоненты импортируются в следующем виде.
import { View, Text, Icon } from '@tarojs/components'
Например, зачем писать с большой буквы, это потому, что вышеexport
То, что выходит, — в верхнем регистре, при этом все компоненты помещаются в один объект. Подумайте еще раз, зачем писать с большой буквы? В конце концов, это может быть сделано для того, чтобы избежать конфликтов имен с собственными компонентами апплета WeChat.taro
заключается в поддержке родного иtaro
Смешанный, если все строчные, как это отличить. Когда вы видите исходный код здесь, вы правыtaro
Является ли правило, что введение компонентов должно быть капитализировано, очень естественным? В то же время мы должны испытать большеtaro
Отсюда вытекает идея компонента. Чем более частыми, но незаметными будут операции, тем больше мы должны испытать на себе ее прекрасные идеи.
Давайте выберем компонент и посмотрим на структуру, напримерButton
компонентов, структура выглядит следующим образом:
Из графика мы можем видетьtaro
Структура кода основных компонентов , отсюда мы можем получить некоторую информацию:
Первый момент: каждый компонент проходит модульное тестирование с использованиемJest
, каталог__test__
Второй момент: каждый компонент имеетindex.md
, документация, описывающая компонент
Третий момент: стиль использует только каталогstyle
для хранения, и имя файла записи используется единообразноindex
Четвертый пункт: вtypes
в каталогеindex.d.ts
настройки файла, делая подсказки кода более удобными
Резюме после анализа @tarojs/components
с учетомtaro
это новая структура, которая имеет большой потенциал, можем ли мы@tarojs/components
Изучите некоторые идеи из исходного кода. Например, когда мы разрабатываем собственную библиотеку компонентов, можем ли мы извлечь уроки из этой идеи? На самом деле структура кода этого компонента в настоящее время очень популярна, например, использование самого популярного фреймворка в этом году.Jest
Фреймворк действует как модульный тест для компонентов, используяts
Делайте подсказки по коду. Смотретьgithub
Если вы используете исходный код на веб-сайте, вы обнаружите, что последнийlerna
инструмент для публикации пакетов, используя облегченныйrollup
упаковочный инструмент, используя@xxx
в видеnamespace
. Вот почему я выбираюtaro
кадр для анализа причин,taro
Он был открыт только в июне 2018 года, поэтому он, должно быть, извлек уроки из новейших передовых технологий и лучших практик без исторического багажа. На самом деле см.taro
После исходного кода вы найдетеtaro
Некоторые концепции дизайна в нем уже превосходят другие известные фреймворки.
Анализ @tarojs/таро
Вы обнаружите, что это все еще установлено в@tarojs
каталог, и никакие другие зависимости не были добавлены.taro
Структура каталогов показана на следующем рисунке.
Из структуры кода на рисунке мы, вероятно, можем знать:
Первый:types
Есть каталогindex.d.ts
, этот файл являетсяts
файл, его роль заключается в написании подсказок по коду. Это даст вам очень полезные советы по спецификации кода при написании кода. Напримерindex.d.ts
В нем есть кусок кода (случайный перехват) следующего содержания:
interface PageConfig {
navigationBarBackgroundColor?: string,
backgroundTextStyle?: 'dark' | 'light',
enablePullDownRefresh?: boolean,
onReachBottomDistance?: number
disableScroll?: boolean
}
Цель этого кода — подсказать вам тип данных этого поля, когда вы пишете соответствующую конфигурацию, давая вам дружественную подсказку. Видя это, на самом деле, мы думаем, что можем добавить такую подсказку и в наш собственный проект, что является хорошей оптимизацией для проекта.
Второе: мы видимdist
каталог, можно сделать вывод, что это выходной каталог, упакованный инструментом упаковки.
Третье: весь каталог очень простой, т.е.taro
Какова роль на самом делеtaro
является средой выполнения.
Давайте взглянемpackage.json
,Как показано ниже:
Нашли поле, т.
"peerDependencies": {
"nervjs": "^1.2.17"
}
Обычно мы используем наиболееdependencies
иdevDependencies
. ТакpeerDependencies
Какое сознание оно выражает? Заходим в Google Translate, как показано на рисунке:
После распаковки перевода даодноранговая зависимость, в сочетании с переводом, поговорим о роли всего поля, что собственно и означает:
Эта зависимость не обязательно должна находиться в собственном каталоге.npm install
. только в корневом каталогеnpm install
Вот и все. В духе того, чтобы не делать колеса, пожалуйста, ознакомьтесь со следующим для конкретной информации.blog
:
Изучите peerDependencies управления зависимостями npm
Давайте взглянемindex.js
, всего две строчки кода:
module.exports = require('./dist/index.js').default
module.exports.default = module.exports
Тем не менее, я был немного удивлен таким способом написания. Зачем так писать, нельзя ли в одну строчку сделать, побольше развязки? Наверное за что.
PS:После написания этой статьи я задумался над этой проблемой и нашел этот способ написания и один из представленных нижеindex.js
Так же пишется:
export {}
export default {}
Сразу понял замысел автора.
анализироватьtaro/src
как показано на рисунке:
Давайте взглянемenv.js
export const ENV_TYPE = {
WEAPP: 'WEAPP',
WEB: 'WEB',
RN: 'RN',
SWAN: 'SWAN',
ALIPAY: 'ALIPAY',
TT: 'TT'
}
export function getEnv () {
if (typeof wx !== 'undefined' && wx.getSystemInfo) {
return ENV_TYPE.WEAPP
}
if (typeof swan !== 'undefined' && swan.getSystemInfo) {
return ENV_TYPE.SWAN
}
if (typeof my !== 'undefined' && my.getSystemInfo) {
return ENV_TYPE.ALIPAY
}
if (typeof tt !== 'undefined' && tt.getSystemInfo) {
return ENV_TYPE.TT
}
if (typeof global !== 'undefined' && global.__fbGenNativeModule) {
return ENV_TYPE.RN
}
if (typeof window !== 'undefined') {
return ENV_TYPE.WEB
}
return 'Unknown environment'
}
Из приведенного выше кода мы видим, чтоgetEnv
функция для получения среды выполнения нашего текущего проекта, напримерweapp
все ещеswan
все ещеtt
и Т. Д. На самом деле, в это время мы должны чувствовать многоконечное единое мышление,genEnv
сделал очень важное дело:
использоватьtaro
После того, как фреймворк напишет код, как конвертировать в мультитерминал? По сути, это переключение на соответствующую среду компиляции согласно среде во время выполнения, тем самым преобразуя ее в код указанного конца. этоgetEnv
Функция может визуализировать этот процесс преобразования.
Продолжим смотреть наindex.js
, код показан ниже:
import Component from './component'
import { get as internal_safe_get } from './internal/safe-get'
import { set as internal_safe_set } from './internal/safe-set'
import { inlineStyle as internal_inline_style } from './internal/inline-style'
import { getOriginal as internal_get_original } from './internal/get-original'
import { getEnv, ENV_TYPE } from './env'
import Events from './events'
import render from './render'
import { noPromiseApis, onAndSyncApis, otherApis, initPxTransform } from './native-apis'
const eventCenter = new Events()
export {
Component, Events, eventCenter, getEnv, ENV_TYPE, render, internal_safe_get, internal_safe_set, internal_inline_style, internal_get_original, noPromiseApis, onAndSyncApis,
otherApis, initPxTransform
}
export default {
Component, Events, eventCenter, getEnv, ENV_TYPE, render, internal_safe_get, internal_safe_set, internal_inline_style, internal_get_original, noPromiseApis, onAndSyncApis,
otherApis, initPxTransform
}
Видно, что с помощьюexport
иexport default
Тот же набор модулей экспортируется. В чем причина этого, я лично думаю, что это для надежности кода. Вы можете смонтировать все экспорты через контекст или деструктурировать, чтобы импортировать определенные экспорты, которые вы хотите. Видя это, можем ли мы также практиковать это в наших собственных проектах?
Нон-стоп, давайте взглянем еще на два важных файла с небольшим количеством кода, один из нихrender.js
, другойcomponent.js
. код показывает, как показано ниже:
render.js
:
export default function render () {}
component.js
:
class Component {
constructor (props) {
this.state = {}
this.props = props || {}
}
}
export default Component
Объем кода очень маленький, пустойrender
функция, функция с несколькими функциямиComponet
Класс, подумайте об этом и знайте, что он делает.
Анализировать глобальный механизм сообщений таро event.js
Давайте взглянемevents.js
, псевдокод (сокращенно) выглядит следующим образом:
class Events {
constructor() {
// ...
}
on() {}
once() {}
off() {}
trigger() {}
}
export default Events
Вы найдете этот файл полнымtaro
глобальный механизм уведомления о сообщениях. Это
имеютon
, once
, off
, trigger
метод,events.js
Имеются соответствующие полные реализации кода. Соответствующие официальные документы:
Подумайте об этом, вы нашлиAPI
Получилось так, понять не так уж и сложно, да и зазубривать не надо.
анализироватьinternal
содержание
Продолжим анализ, также необходимо обратить внимание наinternal
Каталог, в этом каталоге есть введение, см.internal
в каталогеREADME.md
Вы можете знать: он экспортируется вinternal_
Функция, названная в начале, внутренний метод, о котором пользователю не нужно заботиться и который он не будет использовать, будет автоматически предоставляться каждому использованию во время компиляции.taro-cli
Скомпилированный файл плюс его зависимости и используемый. Например:
import { Component } from 'taro'
class C extends Component {
render () {
const { todo } = this.state
return (
<TodoItem
id={todo[0].list[123].id}
/>
)
}
}
будет скомпилирован в:
import { Component, internal_safe_get } from 'taro'
class C extends Component {
$props = {
TodoItem() {
return {
$name: "TodoItem",
id: internal_safe_get(this.state, "todo[0].list[123].id"),
}
}
}
...
}
Во время компиляции он автоматически предоставляется при каждом использованииtaro-cli
Скомпилированный файл плюс его зависимости и используемый. Что означает это предложение? может бытьtaro-cli
При компиляции файл нужно соответствующим образом обработать таким образом. В настоящее время я понимаю это так до поры до времени, и это нормально, что я не могу понять это до поры до времени, и продолжаю анализировать ниже.
анализироватьtarojs/taro
резюме
tarojs/taro
Анализ почти завершен. Из анализа мы получили более общее представление о том, как среда выполнения макроскопически соединяет несколько терминалов и как передатьts
файл, чтобы добавить дружественные подсказки в код. Так как естьinternal
, значит неinternal
Файлы в каталоге могут предоставлять внешние методы, такие какevents.js
, который также может вдохновить нас. Как определить внутренний и внешний код, как разделить.
Проанализируйте несколько сознательных функциональных файлов
Сначала установите зависимости:
yarn add @tarojs/taro-weapp && nervjs && nerv-devtools -S
Затем мы смотрим на последнюю структуру пакета
соответствующийpackage.json
следующее:
{
"dependencies": {
"@tarojs/components": "^1.2.1",
"@tarojs/router": "^1.2.2",
"@tarojs/taro": "^1.2.1",
"@tarojs/taro-weapp": "^1.2.2",
"nerv-devtools": "^1.3.9",
"nervjs": "^1.3.9"
}
}
То есть после того, как мы установим эти зависимости,node_modules
В каталоге ниже так много всего. Давайте кратко рассмотрим косвенно связанные пакеты и выберем несколько, чтобы сказать
анализироватьomit.js
Давайте взглянем:omit.js
import _extends from "babel-runtime/helpers/extends";
function omit(obj, fields) {
var shallowCopy = _extends({}, obj);
for (var i = 0; i < fields.length; i++) {
var key = fields[i];
delete shallowCopy[key];
}
return shallowCopy;
}
export default omit;
отomit.js
изreadme.md
Мы можем знать, что он генерирует объект, который удаляет указанное поле и является поверхностной копией.
анализироватьslash.js
код показывает, как показано ниже:
'use strict';
module.exports = input => {
const isExtendedLengthPath = /^\\\\\?\\/.test(input);
const hasNonAscii = /[^\u0000-\u0080]+/.test(input);
if (isExtendedLengthPath || hasNonAscii) {
return input;
}
return input.replace(/\\/g, '/');
};
отslash
изreadme.md
мы можем знать
This was created since the
path
methods in Node outputs\\
paths on Windows.
Конкретное осознание, проанализируйте сами, это не сложно.
анализироватьvalue-equal.js
value-equal
Основное содержание следующее:
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function valueEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (Array.isArray(a)) {
return Array.isArray(b) && a.length === b.length && a.every(function (item, index) {
return valueEqual(item, b[index]);
});
}
var aType = typeof a === 'undefined' ? 'undefined' : _typeof(a);
var bType = typeof b === 'undefined' ? 'undefined' : _typeof(b);
if (aType !== bType) return false;
if (aType === 'object') {
var aValue = a.valueOf();
var bValue = b.valueOf();
if (aValue !== a || bValue !== b) return valueEqual(aValue, bValue);
var aKeys = Object.keys(a);
var bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) return false;
return aKeys.every(function (key) {
return valueEqual(a[key], b[key]);
});
}
return false;
}
export default valueEqual;
отvalue-equal
изreadme.md
Мы можем знать, что этот метод: только сравнитьkey
соответствующийvalue
ценность. Тщательно прочувствуйте идею написания такого кода.
анализироватьprop-types.js
Давайте взглянемprop-types
, исходный код здесь не указан. СмотретьREADME.md
,мы знаем
Runtime type checking for React props and similar objects.
этоreact
в рамкеprops
Вспомогательный инструмент для проверки типов, то есть для выполнения следующей функции
XxxComponent.propTypes = {
xxProps: PropTypes.xxx
}
Анализировать js-токены
Давайте взглянемjs-tokens
, код показан ниже:
Object.defineProperty(exports, "__esModule", {
value: true
})
exports.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyus]{1,6}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g
комбинироватьREADME.md
, мы обнаружим, что он использует обычныйJS
грамматика становится одна за другойtoken
, so cool.
example
следующее:
var jsTokens = require("js-tokens").default
var jsString = "var foo=opts.foo;\n..."
jsString.match(jsTokens)
// ["var", " ", "foo", "=", "opts", ".", "foo", ";", "\n", ...]
Можете ли вы написать такое антинебесное правило?
Резюме различных небольших функций
Считаете ли вы, что эти функциональные файлы вполне сознательны? Если вы хотите увидеть, как они реализованы, вы можете продолжить просмотр исходного кода. Вы обнаружите, что многие вещи реализованы конкретно, и вам не нужно их запоминать. вообще. Давайте посмотрим на вышеjs-token
, value-equal
, prop-types
omit
, slash
и т. д. На самом деле, все они очень хорошие функции. Они могут вдохновить нас на программирование. Мы можем извлечь уроки из идей и методов реализации этих функций, чтобы лучше улучшить нашу работу.JS
способность к программированию, которая есть и в чтенииnpm
Очень важный урожай в процессе пакета исходного кода.
Анализ @tarojs/taro-weapp
Эта сумка используется дляtaro
Написанный код компилируется в код апплета WeChat, и структура кода показана на рисунке:
Первый изreadme.md
, мы не можем видеть, что делает этот пакет, только одно предложение, базовая структура апплета многотерминального решения. Так что я думаю, что это,taro
Команде еще предстоит дополнить его соответствующим образом. здесьreadme.md
Слишком лаконично написано.
Но мы можем проанализировать это, прочитав кодtaro-weapp
Что он делает?Во-первых, давайте посмотрим на структуру кода. имеютdist
,src
подожди, иnode_modules
. В это время, после того, как мы подумали о пакете, представленном выше, мы задались таким вопросом, почемуnode_modules
содержание. Какова его цель? не могу использовать вышеуказанноеpeerDependencies
реши? В связи с этим я пока не могу понять эту вещь, что мне делать, когда я сталкиваюсь с такой проблемой? В это время мы можем перестать глубоко думать об этой проблеме, чтобы не заблокировать, и продолжить анализировать другие коды.
Смотрим как обычноreadme.md
,ноreadme.md
Информация в одном предложении, основная структура апплета многотерминального решения. Что же делать, не отчаивайтесь! Восемь лет войны, продолжаем анализировать.
Давайте взглянемpackage.json
, часть кода выглядит следующим образом:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rollup -c rollup.config.js",
"watch": "rollup -c rollup.config.js -w"
},
"dependencies": {
"@tarojs/taro": "1.2.2",
"@tarojs/utils": "1.2.2",
"lodash": "^4.17.10",
"prop-types": "^15.6.1"
}
отpackage.json
Мы можем найти две основные вещи, первая - это зависимости, необходимые для этого пакета, вы можете увидеть зависимости@tarojs/taro
, @tarojs/utils
, lodash
, prop-types
.
Затем мы смотрим наnode_modules
, обнаружил, что только@tarojs/taro
. Другие устанавливаются снаружи, такие какlodash
, prop-types
Вы можете использовать пакеты в корневом каталоге, здесь@tarojs/utils
недавно установлен. существуетtaro
Под содержанием. Имея эту информацию на руках, мы объединим вышеуказанное понимание и подумаем над несколькими вопросами:
- почему это не работает
peerDependencies
- зачем ставить
@tarojs/taro
установлен наtaro-weapp
внутри сумки. - Почему
taro-weapp
нетtypes/index.d.ts
такой файл
проблемаmark
На мгновение сначала отбросьте проблему, а потом займитесь глубокими размышлениями. Помните одну вещь, нам не нужно достигать уровня полного понимания при чтении исходного кода, и не обязательно быть реалистом. Все, что нам нужно сделать, это бросить вопрос и перейти к анализу, теперь мы читаемindex.js
, код показан ниже:
module.exports = require('./dist/index.js').default
module.exports.default = module.exports
Это понятноdist
Каталог представляет собой упакованный каталог, теперь давайте его проанализируемsrc
содержание,src
серединаindex
Код файла следующий:
/* eslint-disable camelcase */
import {
getEnv, Events, eventCenter, ENV_TYPE, render,
internal_safe_get, internal_safe_set,
internal_inline_style, internal_get_original
} from '@tarojs/taro'
import Component from './component'
import PureComponent from './pure-component'
import createApp from './create-app'
import createComponent from './create-component'
import initNativeApi from './native-api'
import { getElementById } from './util'
export const Taro = {
Component, PureComponent, createApp, initNativeApi,
Events, eventCenter, getEnv, render, ENV_TYPE,
internal_safe_get, internal_safe_set,
internal_inline_style, createComponent,
internal_get_original, getElementById
}
export default Taro
initNativeApi(Taro)
отindex.js
, мы видим, что импорт@tarojs/taro
некоторые методы. В статье уже проанализировано@tarojs/taro
. Теперь давайте подумаем об этом в сочетании, мы можем найти это: используйте@tarojs/taro-weapp
буду использоватьtaro
Когда написанный код компилируется в апплет WeChat, необходимо использовать@tarojs/taro
пакет для реализации преобразования вместе.
примерно знаюtaro-weapp
эффект. Теперь давайте проанализируемindex.js
Внешние файлы, от которых зависит анализ, следующие:
Анализ src/components.js
Сделайте отступ в коде, давайте посмотрим на общий код, как показано на рисунке:
Как видно из рисунка, полученныйBaseComponent
Класс, вы можете знать из названия, это базовый класс компонентов, так как кода не так много, я буду вставлять его напрямую.
import { enqueueRender } from './render-queue'
import { updateComponent } from './lifecycle'
import { isFunction } from './util'
import {
internal_safe_get as safeGet
} from '@tarojs/taro'
import { cacheDataSet, cacheDataGet } from './data-cache'
const PRELOAD_DATA_KEY = 'preload'
class BaseComponent {
// _createData的时候生成,小程序中通过data.__createData访问
__computed = {}
// this.props,小程序中通过data.__props访问
__props = {}
__isReady = false
// 会在componentDidMount后置为true
__mounted = false
// 删减了一点
$componentType = ''
$router = {
params: {},
path: ''
}
constructor (props = {}, isPage) {
this.state = {}
this.props = props
this.$componentType = isPage ? 'PAGE' : 'COMPONENT'
}
_constructor (props) {
this.props = props || {}
}
_init (scope) {
this.$scope = scope
}
setState (state, callback) {
enqueueRender(this)
}
getState () {
const { _pendingStates, state, props } = this
const queue = _pendingStates.concat()
queue.forEach((nextState) => {
if (isFunction(nextState)) nextState = nextState.call(this, stateClone, props)
Object.assign(stateClone, nextState)
})
return stateClone
}
forceUpdate (callback) {
updateComponent(this)
}
$preload (key, value) { // 省略 }
// 会被匿名函数调用
__triggerPropsFn (key, args) {}
}
export default BaseComponent
Давайте взглянем на приведенный выше код.Из названия мы знаем, что это базовый класс компонента, который можно понять, так как все компоненты должны наследоватьBaseComponent
. Разберем приведенный выше код, сначала разберем первый пункт, почему так много подчеркивающих переменных? На самом деле эти переменные предназначены для собственного использования, давайте посмотрим на следующий код:
class BaseComponent {
// _createData的时候生成,小程序中通过data.__createData访问
__computed = {}
// this.props,小程序中通过data.__props访问
__props = {}
__isReady = false
// 会在componentDidMount后置为true
__mounted = false
// 删减了一点
$componentType = ''
$router = { params: {}, path: ''}
}
Сначала я помнюES6
Не поддерживается запись переменных непосредственно в классе, это нужно делать черезbabel
поддержать его, как написано. По комментариям в коде вы в основном знаете функцию этой переменной, например можно передатьdata.__props
доступ к__props
. этоthis.props
Здесь также используется значение режима прокси. какvue
метод доступа в . Хорошо, мы это поняли, тогда продолжим смотреть на следующий код:
class BaseComponent {
constructor (props = {}, isPage) {
this.state = {}
this.props = props
this.$componentType = isPage ? 'PAGE' : 'COMPONENT'
}
_constructor (props) {
this.props = props || {}
}
}
Смотри, что мы нашли, "конструкторов" два, хахаха, я тебе наврал, конструктор всего один, т.е.constructor
. Но следующее_constructor
Какая, черт возьми, функция, она все еще происходит внутриthis.props = props || {}
Операция, что это за хрень, если вы читалиtaro
В официальной документации вы можете увидеть такую подсказку:
даже если ты не пишешь
this.props = props
, это нормально, потому чтоtaro
Во время работы необходимо использоватьprops
сделай что-нибудь.
Но вы можете не понимать почему, вы всегда чувствуете, что текстовое описание не настоящее из кода, поэтому, когда вы видите приведенный выше код, вы испытываете настоящее чувство, потому что вы видите код.
Фактическиtaro
Используйте свой собственный внутренний метод_constructor
давайthis.props = props || {}
работать. Так документ подскажет, что: не писатьprops
Также может.
другие, такие какsetState
,getState
Подождите, пока сами не проанализируете, путь тот же. В любом случае, пока вы анализируете это, вы можете получить более глубокое понимание этого. Возможно, в этот момент вы забыли о том, что написано в официальной документации сайта, но значение этой строчки в коде вы не забудете.
Проанализируйте src/native-api.js
Код этого файла очень важен, почему он называетсяnative-api
. Если вы посмотрите официальную документацию, вы увидите эту страницу:
На самом деле здесьnative-api.js
Это введение вышеприведенной картины, которую можно понять какTaro
Родной для мини-программ WeChatapi
инкапсуляция выполнена.
Давайте взглянемnative-api.js
Каков результат, код выглядит следующим образом
export default function initNativeApi (taro) {
processApis(taro)
taro.request = request
taro.getCurrentPages = getCurrentPages
taro.getApp = getApp
taro.requirePlugin = requirePlugin
taro.initPxTransform = initPxTransform.bind(taro)
taro.pxTransform = pxTransform.bind(taro)
taro.canIUseWebp = canIUseWebp
}
Здесь, чтобы экспортироватьinitNativeApi
метод. Увидев приведенный выше код, вы знаете общую картину всего входа? Этот экспортированный метод выполняется в записи, чтобыtaro
дополнен. Давайте начнем сtaro-weapp
В файле ввода проверьте, нет ли выполненияinitNativeApi(Taro)
изTaro
Что такое объект, код выглядит следующим образом:
const Taro = {
Component, PureComponent, createApp, initNativeApi, Events,
eventCenter, getEnv, render, ENV_TYPE, internal_safe_get,
internal_safe_set, internal_inline_style,
createComponent, internal_get_original, getElementById
}
Как видно из приведенного выше кода,Taro
как будтоkoa
серединаctx
, многие методы монтируются в виде контекста привязки. Но здесь оптимизация производится путем передачиinitNativeApi(Taro)
способ датьTaro
Смонтируйте больше методов. Посмотрим на исполнениеinitNativeApi(Taro)
ПослеTaro
Что такое объект, код выглядит следующим образом:
const Taro = {
// 上面的导出依然存在,这里不重复写了
request,
getCurrentPages,
getApp,
requirePlugin,
initPxTransform,
pxTransform,
canIUseWebp,
}
processApis(taro)
Не говоря уже об этом.
Мы смотрим на приведенный выше код и обнаруживаем, что есть еще много методов, мы можем понять это, выполнивinitNativeApi(Taro)
, так чтоTaro
Установлен какой-то локальный апплет WeChatAPI
. Но вы обнаружите, что некоторые из них не местныеAPI
, но это можно понять и таким образом, напримерrequest
, getCurrentPages
, getApp
. Я лично понимаю, что причина, по которой автор делает это, заключается в развязке,native
и неnative
метод отдельно.
Анализ src/pure-component.js
import { shallowEqual } from '@tarojs/utils'
import Component from './component'
class PureComponent extends Component {
isPureComponent = true
shouldComponentUpdate (nextProps, nextState) {
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState)
}
}
export default PureComponent
Давайте взглянемpure-componnet.js
код. Вам было очень легко это понять?PureComponent
класс наследуетComponent
. В то же время он осозналshouldComponentUpdate
метод. И этот код метода выглядит следующим образом:
shouldComponentUpdate (nextProps, nextState) {
return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState)
}
Вы обнаружите, что его записьnextProps , nextState
. затем пройтиshallowEqual
Методы иprops
, state
сравнивать, покаshallowEqual
Слушая название, вы понимаете, что это поверхностное сравнение.
Конкретный код находится в@taro/util
в каталогеsrc
в каталогеshallow-equal.js
, код выглядит следующим образом:
Object.is = Object.is || function (x, y) {
if (x === y) return x !== 0 || 1 / x === 1 / y
return x !== x && y !== y
}
export default function shallowEqual (obj1, obj2) {
if (obj1 === null && obj2 === null) return true
if (obj1 === null || obj2 === null) return false
if (Object.is(obj1, obj2)) return true
const obj1Keys = obj1 ? Object.keys(obj1) : []
const obj2Keys = obj2 ? Object.keys(obj2) : []
if (obj1Keys.length !== obj2Keys.length) return false
for (let i = 0; i < obj1Keys.length; i++) {
const obj1KeyItem = obj1Keys[i]
if (!obj2.hasOwnProperty(obj1KeyItem) || !Object.is(obj1[obj1KeyItem], obj2[obj1KeyItem])) {
return false
}
}
return true
}
Глядя на код, я обнаружил, что это поверхностное сравнение. Видишь это, ты чувствуешьPureComponent
Это не так абстрактно и сложно для понимания, как кажется.React
серединаPureComponent
Это тоже причина. Так что нет необходимости запоминать какие-то жизненные циклы фреймворков и различные профессиональные названия. На самом деле, когда вы снимете с нее завесу и увидите ее истину, вы обнаружите, что ее структура не так глубока. Но если у вас просто не хватает мужества поднять завесу и взглянуть ей в лицо, тогда вы будете все время воображать это, не подозревая об истине.
Анализ src/create-componnet.js
Давайте взглянем
const weappComponentConf = {
data: initData,
created (options = {}) {
this.$component = cacheDataGet(preloadInitedComponent, true)
this.$component = new ComponentClass({}, isPage)
this.$component._init(this)
this.$component.render = this.$component._createData
this.$component.__propTypes = ComponentClass.propTypes
Object.assign(this.$component.$router.params, options)
},
attached () {},
ready () {
componentTrigger(this.$component, 'componentDidMount')
},
detached () {
componentTrigger(this.$component, 'componentWillUnmount')
}
}
Из приведенного выше кода мы видим, что это будет использоватьсяtaro
Написанные компоненты компилируются в собственные экземпляры компонентов в программе апплета WeChat. Один момент, на который следует обратить внимание, заключается в том, чтоattached
используется в методеcacheDataGet
иcacheDataHas
, введены два вышеупомянутых метода, почему они здесь используются, какова цель и какой смысл за ними стоит? Нам необходимо рассмотреть и проанализировать значение жизненного цикла компонента апплета WeChat. В то же время мы должны думать об этом предложении в компонентеthis.$component.render = this.$component._createData
Смысл кода, поймите его хорошоcreated
Что именно произошло.
Проанализируйте src/create-app.js
function createApp (AppClass) {
const app = new AppClass()
const weappAppConf = {
onLaunch (options) {
app.$app = this
app.$app.$router = app.$router = {
params: options
}
if (app.componentWillMount) app.componentWillMount()
if (app.componentDidMount) app.componentDidMount()
},
onShow (options) {},
onHide () {},
onError (err) {},
}
return Object.assign(weappAppConf, app)
}
export default createApp
На первый взгляд, мы знаем, что это конфигурация уровня апплета, используемая для создания апплета WeChat.if
заявление, вы можете почувствовать цель за ним. посмотри сноваObject.assign(weappAppConf, app)
знаешь,taro
как следоватьreact
Идея программирования неизменяемых данных.
Проанализируйте src/next-tick.js
const nextTick = (fn, ...args) => {
fn = typeof fn === 'function' ? fn.bind(null, ...args) : fn
const timerFunc = wx.nextTick ? wx.nextTick : setTimeout
timerFunc(fn)
}
export default nextTick
Этот код также легко понять, поместив код вwx.nextTick
илиsetTimeout
для достижения выполнения на следующем этапе цикла.
Проанализируйте src/render-queue.js
import nextTick from './next-tick'
import { updateComponent } from './lifecycle'
let items = []
export function enqueueRender (component) {
if (!component._dirty && (component._dirty = true) && items.push(component) === 1) {
nextTick(rerender)
}
}
export function rerender () {
let p
const list = items
items = []
while ((p = list.pop())) {
if (p._dirty) {
updateComponent(p, true)
}
}
}
Знайте это, назвав егоnextTick
Рендеринг идеи.
Анализ src/lifecycle.js
Мы сжимаем функцию и обнаруживаем, что только экспортupdateComponent
метод, из названия мы знаем, что это обновление осведомленности о компоненте.
Проанализируйте src/data-cache.js
const data = {}
export function cacheDataSet (key, val) {
data[key] = val
}
export function cacheDataGet (key, delelteAfterGet) {
const temp = data[key]
delelteAfterGet && delete data[key]
return temp
}
export function cacheDataHas (key) {
return key in data
}
Мы можем знать из кода, что это для кэширования данных. Сначала кэшируйте, а потом каждый раз извлекайтеvalue
, положи этоvalue
Удалить. Так почему же он спроектирован именно так, каковы причины и каковы преимущества такого дизайна? Вы можете подумать об этом позже, это также хорошая идея для программирования.
анализировать@tarojs/taro-weapp
пострезюме
через пару@tarojs/taro-weapp
Анализ мы знаем конкретно: при беге,taro
черезgetEnv
сократить код доtaro-weapp
среда для компиляции.
Затем мы проанализировали,taro-weapp
Как компилировать и обрабатывать, например, как решить мультитерминалAPI
разные вопросы. Благодаря анализу мы получаем более глубокое пониманиеtaro
Вся архитектурная идея и часть внутренней реализации. Эти идеи стоит попрактиковать в наших обычных проектах. На самом деле, какова цель исходного кода, такого как мой анализtaro init
Из анализа до сих пор, если вы прочитаете его, вы обнаружите, что есть много классных идей.Может быть, в вашем мире вы можете использовать это таким образом, даже если вы написали несколько проектов и не можете их вспомнить. Цель просмотра исходного кода — позволить вам прикоснуться к нему. Как разрабатываются лучшие в мире проекты с открытым исходным кодом. Чтобы впитать эти мысли, использовать их для себя и заставить меня расти.
анализироватьrollup-plugin-alias
отreadme.md
, мы можем обнаружить, что он делает одну вещь, то есть абстрагирует путь введения пакета, который имеет много преимуществ, так что вам не нужно об этом заботиться.../
Этот вид символа может выполнять централизованную модификацию. В чем наше вдохновение, на самом деле, мы можем узнать изrollup-plugin-alias
Научитесь управлять своимиnpm
Сумка. Мы должны усвоить этот тип мышления.
анализироватьresolve-pathname
Что оно делает? В сочетании с исходным кодом изreadme.md
, мы можем обнаружить, что на самом деле он делает то же самое, то есть предоставляет нам метод для работы сURL
, или маршрут, с помощью этого метода мы можем что-то сделать с заданным маршрутом, например, вернуть новый маршрут.
о
invariant、warning
Все они являются вспомогательными инструментами для обработки подсказок, так что не будем об этом, читайте исходники для анализа сами.
Анализ @tarojs/маршрутизатор
Скриншот структуры каталогов кода выглядит следующим образом:
мы увидим вrouter
каталог, естьdist
иtypes
содержание. ноsrc
каталог, но почему некоторые пакеты имеютsrc
Ну есть такие? Это проблема, требующая дальнейшего детального анализа.
Как узнать больше интересного
какnode_modules
Найдите что-нибудь поинтереснее. Позвольте мне привести пример, например, давайте посмотрим наbind
Реализация в разных пакетах:
На картинке нижеcore-js
серединаmodules
в каталогеbind
выполнить
var aFunction = require('./_a-function');
var isObject = require('./_is-object');
var invoke = require('./_invoke');
var arraySlice = [].slice;
var factories = {};
var construct = function (F, len, args) {
if (!(len in factories)) {
for (var n = [], i = 0; i < len; i++) n[i] = 'a[' + i + ']';
factories[len] = Function('F,a', 'return new F(' + n.join(',') + ')');
} return factories[len](F, args);
};
module.exports = Function.bind || function bind(that /* , ...args */) {
var fn = aFunction(this);
var partArgs = arraySlice.call(arguments, 1);
var bound = function (/* args... */) {
var args = partArgs.concat(arraySlice.call(arguments));
return this instanceof bound ? construct(fn, args.length, args) : invoke(fn, args, that);
};
if (isObject(fn.prototype)) bound.prototype = fn.prototype;
return bound;
};
Давайте посмотрим на это сноваlodash
серединаbind
Реализация, код выглядит следующим образом:
var baseRest = require('./_baseRest'),
createWrap = require('./_createWrap'),
getHolder = require('./_getHolder'),
replaceHolders = require('./_replaceHolders');
var WRAP_BIND_FLAG = 1,
WRAP_PARTIAL_FLAG = 32;
var bind = baseRest(function(func, thisArg, partials) {
var bitmask = WRAP_BIND_FLAG;
if (partials.length) {
var holders = replaceHolders(partials, getHolder(bind));
bitmask |= WRAP_PARTIAL_FLAG;
}
return createWrap(func, bitmask, thisArg, partials, holders);
});
bind.placeholder = {};
module.exports = bind;
Сравнивая два кода, мы можем обнаружить, что формы реализации двух кодов различны. Пожалуй, то, что обычно понятно всем, — это первый способ написания, и почти все статьи написаны первым способом, который легко понять. Но второй метод письма более сложен для понимания.По сравнению с первым методом письма, второй метод письма более абстрактный и несвязанный. Например, он более функционален.На самом деле, если вы владеете функциональным программированием,bind
По сути это реализация частичной функции Второй способ написания уже отражен в именовании.partials. Например, в интервью, если спроситьbind
Как это реализовать, можете ли вы написать два метода реализации (идеи программирования)? Может быть, интервьюер не понимает его после того, как вы его написали. Вот пример, их гораздо больше, изучите сами. (Кстатиcore-js
иlodash
вводится пакет. . )
Понимание события пасхального яйца в дизайне муравья
недавнийant design
Пасхальное яйцо, это пасхальное яйцо достаточно захватывающее, чтобы все так бурно отреагировали. достаточно сказатьant design
Популярность, согласно диалекту,ant design
Прежняя идентичность такова: все просто любят и ненавидят, а теперь идентичность такова: все любят и ненавидят.
Если есть проблема, как решить, так и решить, а силу еще надо рвать, кто бы ни брал на себя вину.
История выглядит так:
Например, при работе в компании у коллег или других людей возникают проблемы, поместите свой код
reset
Потерял. Это должно повлиять на вашу работу, что вы будете делать в это время? Ты, должно быть, расстроен, ты, должно быть, ВВ. Особенно когда они сталкиваются с проблемами, которые влияют на работу других людей, они не берут на себя инициативу извиниться и делают вид, что вы можете получить код обратно, если вы этого не сделаете. Вы, должно быть, очень расстраиваетесь, когда встречаете такого человека, и вам хочется найти этого человека, который разорвет вас на части. В конце концов, вы уже повлияли на мою работу, так что не делайте вид, что горшок не ваш. Несите горшок хорошо, и я решу проблемы, которые вы мне принесли. Не делайте этого снова в следующий раз.
иant design
, как и у попавшего в беду коллеги выше, коснулось всех, ноant
Он также проявил инициативу, чтобы признать свою ошибку, и горшок также проявил инициативу, чтобы запомнить ее, и сразу дал план.
На самом деле, я лично считаю, что тем, кто потерял работу из-за этого дела, некомфортнее. Но для тех, кто говорит яростно (неприятно), то есть, рот неприятен, и есть несколько обид, которые в значительной степени поднимутся из-за внешнего интерфейса.Цель неприятности - не что иное, как неявный шпор .ant
команда. я думаюant
Я также понял, что точно больше не буду заниматься подобными вещами в будущем.
Я все еще надеюсь, что вы:
Поскольку мы решили верить с самого началаant design
, тогда у нас больше терпимости, на этот раз терпимостиant design
делать ошибки, не отрицайте их все из-за одной ошибки.
На самом деле вы находитесь в одной компании. Вы совершили ошибку, от которой пострадали многие коллеги. Вы осознали серьезность вопроса. Вам было очень грустно и горько. Вы обнаружили, что делаете крайне глупый поступок. Я очень хочу помириться. за это, но время не может вернуться, время не может вернуться, все, что вы можете сделать, это убедиться, что вы не сделаете ошибок снова в следующий раз, и вы действительно хотите всеобщего прощения и доверия. Хотя ты искренне признаешь свою ошибку, я надеюсь, что все могут доверять тебе по-прежнему, но если все делают ошибку из-за тебя, они не так доверяют тебе в своем поведении и речи. Тогда, в это время, ваше сердце должно быть чрезвычайно потерянным и холодным.
Поэтому я все еще надеюсь, что каждый сможет продолжитьant design
поддерживать доверие, быть инклюзивнымant design
один раз, но и один раз включительноПравильноЛюди, которые внесли большой вклад в открытый исходный код.
На самом деле, иногда в жизни мы обнаруживаем, что терпимости не нужно много раз, достаточно терпимости один раз. Потому что однажды терпимость может сделать так, что что-то никогда не повторится. Нет, это так многословно, но ответ на самом деле в тексте.
Ладно, не будем нести чушь о моем личном мнении.
Примечание
О статье немного длинно
Так как статья действительно длинновата, то я провел некоторые манипуляции с выложенным кодом, например удалил часть кода и записал его в три строки.if
заявление, написанное одной строкой. Пучокimport
, export
Пишите вещи вместе как можно больше, не обертывая. Так что если вы хотите увидеть статью без сокращенной версии, вы можете перейти на мойgithub
Погляди,github
Подключение: https://github.com/godkun/blog/issues/30
Что мне делать, если я столкнусь с чем-то, чего не понимаю при чтении пакета npm
заnpm
Исходный код пакета, когда я его смотрел, тоже не понял некоторых мест, что для нас нормально (NB
Кроме босса) но я не буду блокировать свое понимание всего пакета, потому что я не могу понять определенный абзац или определенный файл.Я добавлю свое понимание, даже если оно неверно, но пока я могу бегло поставить весь пакет Достаточно понять пакет так, как я хочу. Не пытайтесь полностью понять, если вы иnpm
Об этом сообщил автор пакета.
Вы обнаружите, что в этой статье в процессе анализа уже есть некоторые вопросы, и у меня нет однозначного ответа, как и на загруженныхLOL
Обучающие видео, пока они загружены, представляют собой всевозможные классические ходы, предсказания и кокетливые операции. Но на самом деле коленей могло быть больше 10. Говоря об этом, я вдруг подумал о посте на Zhihu.В нем вроде бы спрашивали, что программа обычно пишет код.Также выкладывали картинку Матрицы,спрашивая,так ли это на самом деле? Потом был один, кто ответил видео, и я чуть не рассмеялся, увидев его. На самом деле, выведите это, вы будете знатьnpm
Когда исходный код упакован, плавное плавание невозможно. Должно быть что-то, чего ты не понимаешь, иnpm
источник пакета иgithub
на соответствующемnpm
Исходный код пакета отличается.npm
сумка похожаgithub
Вверхnpm
Исходный код проходит через инструмент управления пакетами,build
после выхода. вам никогда не придетсяdist
Каталог можно увидеть, напримерgithub
серединаtaro
используется в исходном кодеrollup
Упакованы в небольшие пакеты.
Это нормально — столкнуться с чем-то, чего вы не понимаете, вам нужно понять целое и игнорировать части.
Вывод в конце статьи
Прочитав это, вы обнаружите, что я не ставилtaro init
Все зависимости загрузки анализируются один раз, потому что если анализ закончить, то может родиться короткий рассказ, а это бессмысленно. Я всего лишь играю роль привлечения других, надеюсь, вы что-то приобретете после прочтения моей статьи, не бойтесь.npm
Сумка,npm
Пакеты тоже пишутся людьми.
При анализе рекомендую качать один пакет один за другим, а потом качать пакет и смотреть каталог. Это поможет вам понять, что многие людиnpm i
илиyarn install
выключи его, а потом включиnode_modules
каталог, а потом я был ошеломлен, и я не знал, какой пакет искать. Итак, когда вы хотите узнать о чем-то, лучший способ — загружать по одному пакету за раз и просматривать его по частям, чтобы увидеть изменения в структуре кода до и после, а также изменения в пакете. Потом вы обнаружите, что количество упаковок медленно увеличивается, но вы совсем не паникуете, потому что уже примерно знаете их функции и содержимое.
Наконец, в соответствии с операцией, которую преподает учитель китайского языка в начальной школе, давайте сделаем начало и конец эха.
передняя частьgithub
Одна из самых выгодных отраслей в мире, из-за самой передовой технологии с открытым исходным кодом, исходный код находится вgithub
начальство,github
Это сокровище переднего конца, неиссякаемое и неиссякаемое.react
,vue
,angular
,webpack
,babel
,node
,rxjs
,three.js
,TypeScript
,taro
,ant-design
,egg
,jest
,koa
,lodash
,parcel
,rollup
,d3
,redux
,flutter
,cax
,lerna
,hapi
,jsx
,eslint
Подождите, бла-бла, сокровища там, вы хотели бы открыть их и увидеть правду?
Ссылка на ссылку
захватывающий момент
Статьи серии Nuggets можно найти в моемgithub
Найдено на, добро пожаловать, чтобы обсудить, отправить адрес:
https://github.com/godkun/blog
Я думаю, это хорошо, вы можете заказать егоstarи, как, поощрение и поощрение.
Первый раз, когда я раскрыл свой самый загадочный аккаунт на сайте знакомств (дайверский побег)
За кулисами
2018 год подходит к концу, я желаю всем вам счастливой семьи, успешной карьеры и хорошей работы во фронтенд-индустрии в 2019 году.
Велика вероятность, что в этой статье будут ошибки, но велика вероятность, что будут и очень хорошие места.
так............
С Новым годом!