打造一個內部的組件庫,在咱們進行代碼的重構,以及開發新的功能的時候,抽離公共的組件,減小代碼的複用,注重業務與組件的分離,簡化耦合度,便於開發與維護。javascript
最初的時候 考慮過使用vue-cli3.0 vue-loader15+webpack4的配置 後來考慮到穩定性 暫時放棄css
全局配置 babel.config.js 裏的配置默認對整個項目生效,包括node_modules。除非經過 exclude 配置進行剔除。換句話來講babel7擁有全局配置能力。是前端走向將來語法的一大步,改造爲babel7 的時候,遇到了不少難以解決的問題。可是最終仍是堅持下來了。html
從 babel7 開始,全部的官方插件和主要模塊,都放在了 @babel 的命名空間下,從而能夠避免在 npm 倉庫中 babel 相關名稱被搶注的問題前端
Babel7 是對整個項目都生效的配置。vue
移除了以前的stage-x插件,廢棄babel-preset-es201x插件,java
官方升級工具:babel-upgradenode
以前配置的時候,不知道有這個工具,致使走了不少彎路。你們之後在作某個東西的時候,必定要先查查有沒有工具。避免重複造輪子的同時,也能夠避免不少沒必要要的錯誤)。webpack
優化代碼與使用jsV8補丁作效能調校,編譯速度更快。git
webpack中babel-loader的版本不低於@babel/core的版本,不然編譯會報錯es6
以vue-cli 2.9.6版 的版本舉🌰,默認是.babelrc。
.babelrc中的配置和相關的依賴
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2",
],
"plugins": [
"transform-vue-jsx",
"transform-runtime"
],
}
複製代碼
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.22.0",
"@babel/core": "^7.5.5",
複製代碼
mivant中最終版的babel.config.js中的配置和相關依賴
module.exports = function (api) {
api.cache(true);
const presets = [
"@babel/preset-env",
"@vue/babel-preset-app",
[
'@vue/babel-preset-jsx',
{
functional: false
}
]];
const plugins = [
"@babel/plugin-transform-runtime",
'@babel/plugin-transform-object-assign',
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']];
return {
presets,
plugins
};
}
複製代碼
Object.keys(components).forEach((key)=>{
Vue.component(components[key].name,components[key])
})
複製代碼
附index.js中的代碼
import MiButton from './Button/index'
import Modal from './Modal/index'
const components = [
MiButton,
Modal
]
const version = '1.0.0'
const install = function (Vue) {
if (install.installed) return
components.forEach(item => {
Vue.component(item.name, item)
})
}
if (typeof window !== 'undefined' && window.Vue) {
console.log('運行環境爲window');
install(window.Vue)
}
export {
MiButton,
Modal,
install
}
export default {
install,
version
}
複製代碼
// 組件中內置了單個組件所需的樣式 無需配置babel-plugin-import
import { MiButton, Modal } from 'miVant'
import Vue from 'vue'
Vue.use(MiButton)
Vue.use(Modal)
複製代碼
import MiButton from 'miVant/lib/Button'
import Modal from 'miVant/lib/Modal'
import Vue from 'vue'
Vue.use(MiButton)
Vue.use(Modal)
複製代碼
按需架加載的基礎
附錄一段less使用的示例
@hd: 1px; // 基本單位
// 支付寶錢包默認主題
// https://github.com/ant-design/ant-design-mobile/wiki/設計變量表及命名規範
// 色彩
// ---
// 文字色
@color-text-base: #000; // 基本
@color-text-base-inverse: #fff; // 基本 - 反色
@color-text-secondary: #a4a9b0; // 輔助色
@color-text-placeholder: #bbb; // 文本框提示
@color-text-disabled: #bbb; // 失效
@color-text-caption: #888; // 輔助描述
@color-text-paragraph: #333; // 段落
@color-link: @brand-primary; // 連接
@defaultColor: #455a64;
@hoverColor:#1989fa;
@height: 60px;
.navTitle{
font-size:16px;
font-weight:600;
cursor: default;
}
.navItem {
color: @defaultColor;
font: 14px/24px PingFang SC;
padding: 10px 10px 10px 50px;
text-align: left;
cursor: pointer;
}
.doc-nav-title,
.doc-comp-title{
.navItem();
.navTitle();
}
.doc-nav-item{
.navItem()
}
.doc-comp-item{
.navItem()
}
複製代碼
安裝參考指南storybook for vue
自定義的webpack配置,解決擴展名問題和less編譯問題
// 自定義webpack配置
const path = require('path');
module.exports = async ({ config, env }) => {
// Extend it as you need.
function resolve(dir) {
return path.join(__dirname, '..', dir);
}
config.resolve = {
extensions: ['.js', '.vue', '.json', '.jsx'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
},
}
config.module.rules.push({
test: /\.stories.jsx?$/,
loaders: [require.resolve('@storybook/addon-storysource/loader')],
enforce: 'pre',
});
config.module.rules.push(
{
test: /\.(css|less)$/,
use: [{
loader: 'style-loader', // creates style nodes from JS strings
}, {
loader: 'css-loader',// translates CSS into CommonJS
},
{ loader: 'postcss-loader' },
{
loader: 'less-loader',
options: {
javascriptEnabled: true
} // compiles Less to CSS
}],
exclude: /node_modules/
})
return config;
};
複製代碼
storybook 5.0 使用vue-loader15,默認使用babelrc進行解析和編譯,須要自定義babelrc
{
"presets": [
"@babel/preset-env",
"@vue/babel-preset-app",
[
"@vue/babel-preset-jsx",
{
"functional": false
}
]
]
}
複製代碼
stories目錄下 新建 xx.js文件,此處映射爲預覽環境中的 左側預覽目錄
xx.js文件中 引入vue組件,編寫測試案例。經過addDecorator函數引入 插件的相關功能
import { storiesOf } from '@storybook/vue';
import { withKnobs } from '@storybook/addon-knobs';
import miVantButton from '../src/components/Button/Button.vue'
import { withStorySource } from '@storybook/addon-storysource'
import buttonText from '../docs/button.md'
const simpleSourceCode = '<mi-vant-button>storyBook</mi-vant-button>'
storiesOf('miVantButton', module)
.addDecorator(withKnobs)
.addDecorator(withStorySource(simpleSourceCode))
.addParameters({
readme: {
sidebar: buttonText,
},
})
.add('with text', () => {
return {
components: { miVantButton },
template: `<mi-vant-button>storyBook</mi-vant-button>`,
}
},
{
notes: {
markdown: buttonText
}
}
)
複製代碼
根目錄下的.storybook文件夾中
addons.js 中 註冊相關的插件
config.js中 配置容許環境,安裝全局插件。相似於vue項目的main.js
import { configure, addDecorator, addParameters } from '@storybook/vue';
import { withNotes } from '@storybook/addon-notes'
import { addReadme } from 'storybook-readme/vue';
import { setOptions } from '@storybook/addon-options'
import { Button } from 'vant'
import Vue from 'vue'
Vue.use(Button)
const req = require.context('../stories', true, /\.js$/)
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
setOptions({
name: 'mi-Vant',
url: '#',
goFullScreen: false,
showStoriesPanel: true,
showAddonPanel: true,
showSearchBox: true,
addonPanelInRight: true,
sortStoriesByKind: false,
hierarchySeparator: null,
hierarchyRootSeparator: null,
sidebarAnimations: true,
selectedAddonPanel: undefined,
})
addParameters({
viewport: { defaultViewport: 'galaxys5' },
})
addDecorator(addReadme);
addDecorator(withNotes)
// require
configure(loadStories, module);
複製代碼
遇到的問題
新版默認支持vue-loader15 而項目中vue-loader是13.3.0。 當時覺得vue-loader15 是要搭配webpack4 一塊兒使用的 因此下降了一下storybook的版本
低版本的storybook 默認使用babel6 只能解析.babelrc 且須要自定義webpack的配置 因此只能使用storybook中提供的自定義babel和webpack配置
基礎設置都配置好了,在引入插件的時候 發現插件不能用.......... 不知名的報錯 讓人很蛋疼………..,會提示一個語法錯誤。而實際上咱們配置的babel中已經解析了 可是 它仍是會報錯。。。。 猜想與插件版本有關
ReferenceError: regeneratorRuntime is not defined
複製代碼
按需引入vant庫的時候 報了一個css-loader的錯誤
解決辦法:增長exclude
config.module.rules.push(
{
test: /\.(css|less)$/,
use: [{
loader: 'style-loader', // creates style nodes from JS strings
}, {
loader: 'css-loader',// translates CSS into CommonJS
},
{ loader: 'postcss-loader' },
{
loader: 'less-loader',
options: {
javascriptEnabled: true
} // compiles Less to CSS
}],
exclude: /node_modules/
})
複製代碼
最終選擇了 目前的穩定版,更改了相關的配置 並引入相關的插件
插件名稱 | 功能 | 備註 |
---|---|---|
@storybook/addon-notes | 組件中添加notes,裝飾story | 註釋文本信息 |
@storybook/addon-actions | 展現event數據 | |
@storybook/addon-backgrounds | 改變頁面的背景色 | |
@storybook/addon-storysource | 展現組件源碼 | |
@storybook/addon-knobs | 動態展現props | |
storybook-readme | 將markdown導入爲story | |
@storybook/addon-viewport/register | 增長移動端預覽模式 | |
@storybook/addon-options | 配置面板選型 |
相關文檔
Storybook 5.0 正式發佈:有史以來變化最大的版本
Rollup 是一個 JavaScript 模塊打包器,能夠將小塊代碼編譯成大塊複雜的代碼,例如 library 或應用程序。採用 es6 原生的模塊機制進行模塊的打包構建, 編譯以後包 體積會更小。
sudo npm install --global cross-env
複製代碼
建議想嘗試的同窗 使用babel6 + babelrc這樣的配置
chenshenhai.github.io/rollupjs-no…
附rollup.config.prod.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import buble from 'rollup-plugin-buble'
import replace from 'rollup-plugin-replace';
import { uglify } from 'rollup-plugin-uglify';
import vue from 'rollup-plugin-vue'
import postcss from 'rollup-plugin-postcss';
const path = require('path');
const ENV = process.env.NODE_ENV;
const resolveFile = function (filePath) {
return path.join(__dirname, './', filePath)
}
export default {
input: resolveFile('src/components/index.js'),
output: {
dir: 'es',
format: 'umd',
name: 'miVant',
exports: 'named',
},
plugins: [
resolve({ extensions: ['.js', '.vue'] }),
postcss({
extensions: ['.less', '.css'],
use: [
['less', {
javascriptEnabled: true
}]
],
extract: true,
minimize: true,
}),
vue({
template: {
isProduction: true
},
css: false
}),
commonjs(),
buble({
objectAssign: 'Object.assign'
}),
replace({
exclude: 'node_modules/**',
ENV: JSON.stringify(process.env.NODE_ENV),
}),
(ENV === 'production' && uglify()),
],
};
複製代碼
I want
因爲以前沒有接觸過相似的功能,因而漫漫的調研之路開始了。。。。
附webpack中關於markdown的解析規則
{
test: /\.md$/,
use: [
{
loader: 'vue-loader'
},
{
loader: 'vue-markdown-loader/lib/markdown-compiler',
options: {
raw: true,
preventExtract: true,
use: [
[
require('markdown-it-container'),
'demo',
{
validate: function (params) {
return params.trim().match(/^demo\s+(.*)$/)
},
render: function (tokens, idx) {
if (tokens[idx].nesting === 1) {
// 1.獲取第一行的內容使用markdown渲染html做爲組件的描述
let demoInfo = tokens[idx].info.trim().match(/^demo\s+(.*)$/)
let description = demoInfo && demoInfo.length > 1 ? demoInfo[1] : ''
let descriptionHTML = description ? markdownRender.render(description) : ''
// 2.獲取代碼塊內的html和js代碼
let content = tokens[idx + 1].content
// 3.使用自定義開發組件【DemoBlock】來包裹內容而且渲染成案例和代碼示例
return `<demo-block> <div class="source" slot="source">${content}</div> ${descriptionHTML} <div class="highlight" slot="highlight">`
} else {
return '</div></demo-block>\n'
}
}
}
]
]
}
}
]
},
複製代碼
demo-block中手動補充copy功能
<template>
<div class="demo-block">
<div class="demo-block-source">
<slot name="source"></slot>
<span class="demo-block-code-icon" v-if="!$slots.default" @click="showCode=!showCode">
<img
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/wSAkBuJFbdxsosKKpqyq.svg"
class="code-expand-icon-show"
/>
</span>
</div>
<div class="demo-block-meta" v-if="$slots.default">
<slot></slot>
<span v-if="$slots.default" class="demo-block-code-icon" @click="showCode=!showCode">
<img
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/wSAkBuJFbdxsosKKpqyq.svg"
class="code-expand-icon-show"
/>
</span>
</div>
<div class="demo-block-code" v-show="showCode">
<p class="copy" @click="copy">複製</p>
<slot name="highlight"></slot>
</div>
</div>
</template>
<script type="text/babel">
export default {
data() {
return {
showCode: false
};
},
methods: {
copy(e) {
const hightext = e.target.nextElementSibling;
const input = document.createElement("input");
document.body.appendChild(input);
let value = hightext.innerText;
input.value = value;
input.select();
if (document.execCommand("copy")) {
document.execCommand("copy");
console.log("複製成功");
}
document.body.removeChild(input);
}
}
};
</script>
<style lang='less'>
@import "./less/demo-block.less";
.copy {
cursor: pointer;
position: absolute;
right: 10px;
top: 0;
}
</style>
複製代碼
VuePress 手摸手教你搭建一個類Vue文檔風格的技術文檔/博客
從 Vue-cli 開始構建 UI 庫到 Markdown 生成文檔和演示案例
vue-markdown-loader error with vue Loader 15
rem的適配功能
經過postcss-px2rem將px單位自動轉化爲rem單位
經過項目根目錄下的.postcssrc.js 設置轉化規則
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {
browsers: ['Android >= 4.0', 'iOS >= 7']
},
"postcss-px2rem": { remUnit: 100 }
}
}
複製代碼
css中補充對應的font-size大小
@import './var.less';
html {
font-size: 100px; /* no */
}
h1{
font-size: 32px;
}
h2{
font-size: 24px;
}
h3{
font-size: 19px;
}
h4{
font-size: 16px;
}
h5{
font-size: 14px;
}
h6{
font-size: 13px;
}
li,p,th,td {
font-size: 16px;
}
複製代碼
定製主題
miVant 使用了 Less 對樣式進行預處理,並內置了一些樣式變量,經過替換樣式變量便可定製你本身須要的主題。
配置文件: ~/src/components/less/var.less
@primary-btn-color :#fbb212;
複製代碼
定製方法
exports.cssLoaders = function (options) {
options = options || {}
const lessLoader = {
loader: 'less-loader',
options: {
sourceMap: options.sourceMap,
modifyVars: {
color: 'red'
}
}
}
const lessConfig = {
modifyVars: {
primary-btn-color: 'red'
}
};
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders(loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader, lessLoader] : [cssLoader, lessLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less', lessConfig),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
複製代碼
// 克隆項目到本地
git clone https://github.com/majunchang/mi-vant.git
// 切換到master分支
// 安裝相關依賴
npm i
// npm 腳本
// storybook 預覽模式
"start": "npm run storybook",
"storybook": "start-storybook -p 9001 -c .storybook",
// 打包storybook靜態文件
"build-storybook": "build-storybook -c .storybook",
// 文檔預覽 端口是8081
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
// 打包以後的依賴包分析
"bundle-report": "webpack-bundle-analyzer --port 8123 dist/stats.json",
// webpack build
"build": "node build/build.js",
// rollup 編譯
"clean": "rimraf rollupDist",
"rollup": "cross-env NODE_ENV=production rollup --config=rollup.config.prod.js"
複製代碼