I just released the VC-Popup component set, but at that time it was just showing how to use it, because I was in a hurry to publish it, so I’m sorry ~
Vc-popup is only a collection of popup components, not a complete library of popups, so most of the time, users only want to use one popup, then other pop-ups are packaged, which will waste bandwidth. So each popup needs to be released to NPM separately, but separating dependencies can be inconvenient for later development. For example, when one package is updated, the other needs to be updated manually. To solve this inconvenience, Lerna is introduced to facilitate the development and management of multiple packages
However, I have encountered some problems and stepped on some holes in the process of practice, so I will record here. But before I start, I will mention the update of VC-Popup first
12-08: imgView Supports lazy loading of imgView. The synchronization changes from the preset image loading status to the loaded SRC
Install Lerna
If you use VScode, you can use –by= NPM to avoid rg.exe CPU problems. Similarly, you can set –by=yarn. If you use CNPM to install some packages, you can use CNPM only to download. Assign the installation to NPM /yarn
> npm i -g lerna
> cnpm i -g lerna --by=npm
> yarn global add lerna
Copy the code
Initialize a demo
In the daily use of input commands commonly used **&& to speed up the efficiency, I input more times, only to find that the advantage of the command line compared with the interface is that you can series a number of simple tasks, this semester began to learn the operating system, found that there is a similar noun single batch processing system and CMD batch script **, When you press the {enter} key, what other commands can you type in ahead of time
Another advantage is that commands are determined based on character combinations, not interface positions, so interfaces need to be layered, naming is not required, and character combinations are large
> mkdir lerna-demo && cd lerna-demo && lerna init
Copy the code
Because CNPM needs to be inserted in front, the installation part is not connected in series
Due to the shift key on the right side of the keyboard, the input of && is not so smooth, you can use AHK to switch, I usually use the laptop keyboard aand{space} to generate &&{space}, because after adjusting the shift position, I still press &&
Generated view generated files and directories
> ls
lerna.json package.json packages
Copy the code
View the file contents separately
> head lerna.json && head package.json{" lerna ":" 2.5.1 ", "packages" : [" packages / * "], "version" : "0.0.0"} {" devDependencies ": {" lerna" : "^ 2.5.1"}}Copy the code
Then create a new directory, s
> cd packages && mkdir module-0 module-1 module-2
Copy the code
Initialization package. Json
> cd module-0 && npm init -y && cd ../module-1 && npm init -y && cd ../module-2 && npm init -yWrote to D:\DEV\Github\demo\lerna-demo\packages\module-0\package.json: { "name": "module-0", "version": "1.0.0", "main": "index.js", "scripts": {"test": "echo \"Error: no test specified\" && exit 1"}, "keywords": [], "author": "", "license": "ISC", "description": "" } Wrote to D:\DEV\Github\demo\lerna-demo\packages\module-1\package.json: { "name": "module-1", "version": "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ", "echo \" Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } Wrote to D:\DEV\Github\demo\lerna-demo\packages\module-2\package.json: { "name": "module-2", "version": "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ", "echo \" Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }Copy the code
Initialize index.js for each module
> echo export default require('./package.json').name > index.js && cat index.js > .. /module-0/index.js && cat index.js > .. /module-1/index.js
Copy the code
Create index.js in lerna-demo and edit it. Since lerna maintains dependencies between Packages /*, the index.js in lerna will directly fill in the path of Mode-2
> cd ../.. && code index.js
Copy the code
const msg = require('./packages/module-2')
console.log(msg);
Copy the code
To set dependencies between modules, you can now fill in the corresponding module when require
Modify the index.js of module-1
export default
require('./package.json').name
+ 'depends on [' + require('module-0').default + '] '
Copy the code
Modify the index.js of Module-2
export default
require('./package.json').name
+ 'depends on [' + require('module-1').default + '] '
Copy the code
thinking
What is the normal way to add NPM package dependencies? yarn add modue-name
What’s the result? It downloads the package from the NPM repository, decompress it to node_modules/modul -name, and then processes the packsage
So does that mean that Lerna is going to do something similar? If you are developing Module-2, but you find a bug in Module-1, you need to release the bug to NPM, and then Module-2 updates the dependency of Module-1, then you can guess that Leran automated the update by some means
So based on the guess can be verified ~ ~ first read the manual, check this similar operation is what ~
This is clear from Example, so start generating dependencies
> lerna add module-0 --scope=module-1
> lerna add module-1 --scope=module-2
Copy the code
The expected result is that node_modules of Module-2 has the folder of Module-1 and contains its contents, as does module-1
So you can guess how
Is it recursively copying files? Then, check module-1/node_modules/module-0/index.js, the same with module-2
Set module-0/index.js as follows
export default
require('./package.json').name + ' edited'
Copy the code
OK, auto-change is synchronous, so it’s not, remember when you looked at the Linux tutorial there was a tool that was related, ln, but I’m using the file system that’s NTFS
> ver
Microsoft Windows [Version 10.0.15063]
Copy the code
> ln --help Usage: ln [option]... [-t] Target link name (first format) or: ln [option]... Target (second format) or: ln [option]... The target... Directory (third format) or: ln [option]... -t Directory target... In the 1st form, create a link to TARGET with the name LINK_NAME. In the 2nd form, create a link to TARGET in the current directory. In the 3rd and 4th forms, create links to each TARGET in DIRECTORY. Create hard links by default, symbolic links with --symbolic. By default, each destination (name of new link) should not already exist. When creating hard links, each TARGET must exist. Symbolic links can hold arbitrary text; if later resolved, a relative link is interpreted in relation to its parent directory. --moreCopy the code
But I use Windows oh, so guess is through Windows tools to achieve, at this time, I suddenly thought of many times to reinstall the system learned on the Internet skills
> mklink --help
The syntax of the command is incorrect.
Creates a symbolic link.
MKLINK [[/D] | [/H] | [/J]] Link Target
/D Creates a directory symbolic link. Default is a file
symbolic link.
/H Creates a hard link instead of a symbolic link.
/J Creates a Directory Junction.
Link Specifies the new symbolic link name.
Target Specifies the path (relative or absolute) that the new link
refers to.
Copy the code
Before reinstalling the system, will be through the MKlink C disk Users Juction to D disk, after each time to restore the system when some of the configuration of the program will not have to reset, the specific can refer to the online tutorial, when the system needs to install the operation (file decompression, but has not restarted, When booting the installation), remember that it does not seem to work after the system is installed
If cygwin is installed and the bin directory is in the path, you need to use dir instead
In Windows, lerna builds Juction to solve the dependency synchronization problem. In Linux, lerna uses a similar tool ln~
Set Babel transcoding with webpack and verify the result with lerna-demo/index.out.js
> webpack && node index.out.jsHash: 3378d33b254656002585 Version: Webpack 3.10.0 Time: 1031ms Asset Size Chunks Names index.out.js 4.14KB 0 [emitted by a Chunk] main [0]./index.js 83 bytes {0} [built] [1] ./packages/module-2/index.js 183 bytes {0} [built] [2] ./packages/module-2/package.json 233 bytes {0} [built] [3] ./packages/module-1/index.js 183 bytes {0} [built] [4] ./packages/module-1/package.json 233 bytes {0} [built] [5] ./packages/module-0/index.js 141 bytes {0} [built] [6] ./packages/module-0/package.json 196 bytes {0} [built] module-2 depends on [module-1 depends on [module-0 edited]]Copy the code
The result is out. The demo test has passed. Now let’s think about what problems may occur when we transform vC-popup. Lerna solves dependencies in **packages/**, which brings us back to the example
const msg = require('./packages/module-2')
console.log(msg);
Copy the code
What is indicated here is that you cannot enjoy the benefits of relying on update synchronization if you are not in the Packages folder
starts
Any experimental modifications are recommended in the new branch
> git checkout -b split-packages
Copy the code
The overall idea is roughly the same as lerna-Demo, but the difference is that it can be customized according to the existing directory structure, so the following will briefly talk about the idea and problems encountered.
The directory structure
> tree src Folder PATH listing for volume Data Volume serial number is 0007-86B5 D:\DEV\GITHUB\OPENSOURCE\VC-POPUP\SRC ├ ─ ─ ─ components │ ├ ─ ─ ─ gesture - tiles - press │ ├ ─ ─ ─ picker - view │ ├ ─ ─ ─ popup - base │ ├ ─ ─ ─ popup - bottom - menu │ ├ ─ ─ ─ popup - by - animation │ ├ ─ ─ ─ popup calendar - │ ├ ─ ─ ─ popup - center - menu │ ├ ─ ─ ─ popup datetime - picker │ ├ ─ ─ ─ popup dialog - │ ├ ─ ─ ─ popup - the dom - relative │ ├ ─ ─ ─ popup - img - viewer │ ├ ─ ─ ─ popup - over │ ├ ─ ─ ─ popup - picker │ ├ ─ ─ ─ popup - press - menu │ ├ ─ ─ ─ the pull - down - refresh │ ├ ─ ─ ─ swipe - item │ └ ─ ─ ─ swipeplus ├ ─ ─ ─ mixins │ └ ─ ─ ─ the event └ ─ ─ ─ utilsCopy the code
Analysis of the
SRC /components/popup-* The generated package is vc-popup-* and the entry is index.js
import Vue from 'vue'
import popup from 'vc-popup-*'
Vue.use(popup)
Copy the code
After unpacking, popup-* packages and dependencies between packages are external
The install function in vue. use installs the dependent popup first
The profile
- Initialized with JS
popup-*
Directory andpackage.json
- Each is generated via JS
popup
theentry[install.js]
- configuration
webpack.pkg.conf.js
, configure multiple entrances - Lerna sets dependencies between packages that all other packages need to rely on
popup-base
- experimental
popup
Through thepackage.json
Set up theprivate: true
Don’t put it out
A total of 3 files need to be created, two are batch properties, one is webpack configuration, the main point is the configuration of multiple entries, relatively simple
Points to note
How to inject vue dependencies?
Set to external dependencies when webPack is packaged? Then popup internally uses import Vue from ‘Vue’?
Or should I rely on the Vue when executing vue.use ()?
The difference is whether to use WebPack for project building (or another packaging tool). It is not clear whether external dependencies declared in modules packaged with WebPack are compatible with other tools.
If you inject Vue’s dependencies through vue.use (), you’ll be more compatible with projects that don’t use WebPack for builds
I am speechless line…
If you need to import popup from ‘vc-popup-*’, you need to import popup from ‘vc-popup-*’. So embrace the es6 module. [laughs awkwardly]
How are packages tested before they are published to NPM
The first few tests are published to NPM and then updated and tested. In fact, it is not necessary, after the build is completed, the updated files are synchronized to the node_modules folder of the previous test project, which is much more efficient. In this case, the junction method is used to synchronize the updated files
However, it is best to document the use of custom Juction, and write the Settings of juction into the initialization script. It is best to write platform compatible, NTFS use mklink, Linux use ln
It is also possible to use file copy to synchronize, but be careful not to delete node_modules/vc-popup-base and then copy the folder, because when you start dev Server, it will break because you can’t find the folder and you need to open it again. So just overwrite the file
Well, publish after testing, not after publish!
Specific steps
generatepopup-*
Directory, and package.json
var fs = require('fs')
var path = require('path')
var readlineSync = require('readline-sync');
var deleteFolderRecursive = require('./utils').deleteFolderRecursive;
require('shelljs/global');
// Utility functions
function _path(str){
return path.resolve(__dirname, str)
}
function _package(name){
return `{
"name": "vc-${name}",
"version": "0.0.0",
"description": "vc-${name}",
"main": "index.js",
"scripts": {
"test": "echo hasn't write test~"
},
"author": "deepkolos",
"license": "MIT",
"dependencies": {}
}`;
}
function initpkg(dirname){
var path = _path('.. /packages/'+dirname);
if( !fs.existsSync(path) ){
fs.mkdirSync(path);
fs.writeFileSync(path+'/package.json', _package(dirname)); }}/ /
var deleteAllDir = readlineSync.question('Clear all directories under Packages? (y/n)');
var componentsDir = fs.readdirSync(
_path('.. /src/components'), {
encoding: "utf8"
});
deleteAllDir.toLowerCase() == 'y' &&
componentsDir.map((dirname) = > {
deleteFolderRecursive(_path('.. /packages/'+dirname))
})
componentsDir.map(dirname= > {
if(dirname.indexOf('popup-') = = =0)
initpkg(dirname)
});
Copy the code
generatepopup-*
Directory, entery [the js]
var fs = require('fs')
var render = require('json-templater/string')
var uppercamelcase = require('uppercamelcase')
var path = require('path')
var utils = require('./utils')
var p = function (str){
return path.resolve(__dirname, str);
}
var PACKAGE_PATH = p('.. /packages')
var DEPENDANCE_TEMPLATE = ` Vue.use(require('{{name}}'))`
var MAIN_TEMPLATE = ` const version = '{{version}}' const install = function (Vue, config = {}) { if (install.installed) return {{includeDepend}} require('{{self}}') } // auto install if (typeof window ! == 'undefined' && window.Vue) { install(window.Vue) } export default { install, version } `
var BASE_MAIN_TEMPLATE = ` import { popupRegister, importVue } from '{{self}}' const version = '{{version}}' const install = function (Vue, config = {}) { if (install.installed) return {{includeDepend}} importVue(Vue) require('{{self}}').default.init(Vue) } // auto install if (typeof window ! == 'undefined' && window.Vue) { install(window.Vue) } export default { install, version, popupRegister } `
function build_install(popupName){
var pkg = require(`${PACKAGE_PATH}/${popupName}/package.json`)
var version = pkg.version
var dependanceList = []
var tpl = popupName === 'popup-base'? BASE_MAIN_TEMPLATE: MAIN_TEMPLATE
pkg.dependencies &&
Object.keys(pkg.dependencies).forEach(function(depName){
dependanceList.push(render(DEPENDANCE_TEMPLATE, {
name: depName
}))
});
var template = render(tpl, {
includeDepend: dependanceList.join('\n'),
version: version,
self: `.. /.. /src/components/${popupName}`
})
fs.writeFileSync(p(`.. /packages/${popupName}/install.js`), template);
}
/ /
utils.mapPkgList(function(popupName){
build_install(popupName)
})
Copy the code
Configure multiple portals for WebPack
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true})},devtool: config.build.productionSourceMap ? '#source-map' : false.externals: ['vue'.'vc-popup-base'].// Setting external dependencies is relatively simple
plugins: [
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
})
]
})
fs.readdirSync(path.resolve(__dirname, '.. /packages'));
webpackConfig.entry = {}
webpackConfig.output = {
path: path.resolve(__dirname, '.. /packages/'),
filename: `[name]/index.js`.libraryExport: "default".libraryTarget: "umd"
}
utils.mapPkgList(function(popupName){
webpackConfig.entry[popupName] =
path.resolve(__dirname, `.. /packages/${popupName}/install.js`)})module.exports = webpackConfig
Copy the code
The rest of the steps are the same as for Lerna-demo
release
> lerna publish
Copy the code
done~
Unpacking of mainstream VUE component libraries
I have read the general construction ideas of Mint-UI, Vant, WE-vue, Weex-UI, Cube-UI and Fish-UI
Only mint-ui and Weex-UI use Lerna to unpack from design. Vant has packages but does not include package.json
While weex-UI uses lerna to unpack, package.json directly uses the source code as the entry
Mint-ui seems to be the most standard component library. At the build level, the unwrapped packages also contain the source code, and the exit of package.json is compiled
While my VC-popup structure is a hybrid, I didn’t consider unpacking at the beginning, but added it later, so… Unpacked packages contain only compiled files… No separation of JS, CSS…
As for whether the subcomponent package needs to be compiled again, The Cube-UI Didi team has a post-compilation optimization suggestion, which is reasonable in my opinion. Components will be compiled at another level in the specific VUE project, so only the source code can be released when the component is released, but I still think mint-UI is the most standard way ~~
Finally, ask for suggestions for the article
It seems to be a little bit of a digressade [Faceplam], but also because, in fact, after you get the idea out of the way, the next thing to do is code and debug
I would like to ask, like at the beginning there interspersed with a variety of small skills, and a bit of understanding of things, I do not know what you think of this way? In fact, I usually have some small understanding, but not enough to write, so I intend to put these small knowledge inserted into the relevant specific instances, if you feel the front part is good, then click like, I intend to use this small knowledge sharing style ~
I hope you give my article to give advice ~ is mainly to share the above ideas, or to the summary of practice above what good methods or ideas, guidance guidance ~
The documentation used by VC-Popup is not complete yet, here is an excuse to write an article for myself ~