-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.json
1 lines (1 loc) · 42.4 KB
/
search.json
1
[{"title":"前端工具库开发","url":"/2023/03/10/%E5%89%8D%E7%AB%AF%E5%B7%A5%E5%85%B7%E5%BA%93%E5%BC%80%E5%8F%91/","content":"前言本文将介绍如何开发一个前端工具库,并使用rollup对代码进行打包,最终将工具库发布到npm\n\nRollup 是一个 JavaScript 模块打包工具,可以将多个小的代码片段编译为完整的库和应用。文档\n\n想要完整地发布一个工具库,分为以下步骤:\n\n初始化项目,并安装相关依赖\n修改package.json中的相关配置\n如果你的工具包是使用typescript编写的,还需要额外配置一下tsconfig.json\n使用rollup打包代码\n发布npm包\n\n安装依赖\nrollup:用于打包 JavaScript 应用程序和库的模块打包器\nrollup-plugin-typescript2:用于在 Rollup 构建过程中编译 TypeScript 代码\ntypescript:rollup-plugin-typescript2 的对等依赖项\ntslib:rollup-plugin-typescript2 的对等依赖项\n@rollup/plugin-json:用于将 .json 文件转换为 ES6 模块\n\nnpm i rollup rollup-plugin-typescript2 tslib typescript @rollup/plugin-json -D\n\n配置文件配置package.json:\n { "name": "my-lib", "version": "1.0.0", "description": "...", "main": "lib/index.js", // 项目入口文件, commonjs 规范的代码 "module": "es/index.js", // esm 规范的代码的入口文件,优先级比 main 高 "type": "module", // 定义 package.json 文件和该文件所在目录根目录中.js文件和无拓展名文件的处理方式。值为 moduel 则当作 es 模块处理;值为 commonjs 则被当作commonJs模块处理 "typings": "index.d.ts", // .d.ts声明文件的入口 "files": [ "es", "lib" ], // 项目中要发布的文件列表 "scripts": { "build": "rollup -c rollup.config.ts --configPlugin typescript --environment NODE_ENV=production", "dev": "rollup -c rollup.config.ts --configPlugin typescript" }, "devDependencies": {...}}\n\n配置rollup.config.ts:\nimport json from '@rollup/plugin-json'import typescript from 'rollup-plugin-typescript2'import { readFileSync } from 'fs'export default { input: 'src/index.ts', output: [ { name: pkg.name, file: pkg.main, format: 'umd', sourcemap: !isProduction, }, { name: pkg.name, file: pkg.module, format: 'es', sourcemap: !isProduction, } ], plugins: [ json(), typescript(), ]}\n\n使用第三方类库我们在开发过程中,可能会依赖一些外部类库,如:lodash、react。\n为了保证其中的模块能够正常的,通常都会需要使用到@rollup/plugin-commonjs。该插件支持将 CommonJS 模块转换为ES6,可以帮助我们在项目中使用commonjs规范的文件/模块。\n另外,我们在打包的时候应该注意保持这些类库的外部引用状态,并告诉rollup如何正确的处理这些依赖。\n最后,为了确保这些外部类库的代码不会被共同打包到bundle.js文件中。可以使用external属性,告诉rollup哪些是外部的库,不需要对这些外部类库进行打包。\n安装:\nnpm install @rollup/plugin-commonjs @rollup/plugin-node-resolve --save-dev\n\n使用:\nimport commonjs from '@rollup/plugin-commonjs';import { nodeResolve } from '@rollup/plugin-node-resolve'export default { input: 'src/index.js', output: [ { // ... format: 'umd', globals: { 'lodash': 'lodash' } } ], plugins: [ \tnodeResolve(), commonjs() ], external: ['lodash'],};\n\nTree Shaking & 副作用代码在使用rollup进行生产构建的时候,会自动开启tree shaking,其本质是借助ES Module的静态分析来消除无用的js代码。无用代码有以下特征:\n\n代码不会被执行到\n代码执行的结果不会被用到\n代码只影响死变量\n\n为了更直观的体会tree shaking的作用,我们可以看看rollup官方示例:\nmain.js\n// TREE-SHAKINGimport { cube } from './maths.js';console.log(cube(5)); // 125\n\nmaths.js\n// maths.js// This function isn't used anywhere, so// Rollup excludes it from the bundle...export const square = x => x * x;// This function gets included// rewrite this as `square(x) * x`// and see what happens!export const cube = x => x * x * x;// This "side effect" creates a global// variable and will not be removed.window.effect1 = 'created';const includeEffect = false;if (includeEffect) {\t// On the other hand, this is never\t// executed and thus removed.\twindow.effect1 = 'not created';}\n\nbundle comes out:\n// maths.js// This function gets included// rewrite this as `square(x) * x`// and see what happens!const cube = x => x * x * x;// This "side effect" creates a global// variable and will not be removed.window.effect1 = 'created';// TREE-SHAKINGconsole.log(cube(5)); // 125\n\n可以看到,没有被使用到的代码都被’摇’掉了。可是产生了副作用的一段代码仍然被保留了下来:\nwindow.effect1 = 'created';\n\n以下操作同样会产生副作用:\n\nglobal, document, window, 全局变量修改,如window.xxx = xx\nconsole.log,history.pushState等方法调用\n未声明的变量,如a = 1\n\n处理副作用代码有时候,我们并不希望意外的副作用代码被保留下来,以此避免产生一些不必要的错误。\ntreeshake.annotations\n在代码注释中忽略副作用\n/*@__PURE__*/ console.log('side-effect');class Impure {\tconstructor() {\t\tconsole.log('side-effect');\t}}/*@__PURE__*/ new Impure();\n\ntreeshake.moduleSideEffects\n忽略模块的副作用\n// input fileimport { unused } from 'external-a';import 'external-b';console.log(42);\n\n// output with treeshake.moduleSideEffects === trueimport 'external-a';import 'external-b';console.log(42);\n\n// output with treeshake.moduleSideEffects === falseconsole.log(42);\n\n更多选项请参考官方文档。使用配置项:\n// rollup.config.jsexport default {\t// ... treeshake: { \tpropertyReadSideEffects: false, \tmoduleSideEffects: false, \t// ...\t}}\n\n提示:使用SideEffects前请确保你的代码真的没有副作用,否则打包的时候会误删掉那些有副作用的代码\n生成声明文件由于我们使用了typescript,在发布代码之前,也应该让同样使用typescript的用户能够进行类型提示。\n这里我们使用rollup-plugin-dts,该插件能够汇总你的.d.ts定义文件。该插件会自动将任何外部库(@types例如)标记为external,因此这些库将被排除在捆绑之外。\n安装:\nnpm install --save-dev rollup-plugin-dts\n\n将其添加到rollup.config.js:\nexport default [ //... { input: "./my-input/index.d.ts", output: [{ file: "dist/my-library.d.ts", format: "es" }], plugins: [dts()], },]\n\n并且修改package.json配置项:\n{\t"types": "dist/my-library.d.ts", // 用于指定包含项目的类型声明文件的目录}// 或者{ "typings": "dist/my-library.d.ts" // 用于指定包含项目类型声明文件的文件名}\n\n执行构建命令npm run build\n\n{\t"scripts": { "build": "rollup -c rollup.config.ts --environment NODE_ENV=production --configPlugin typescript" },}\n\n发布npm publish\n","categories":["前端"],"tags":["npm"]},{"title":"前端脚手架开发","url":"/2023/04/06/%E5%89%8D%E7%AB%AF%E8%84%9A%E6%89%8B%E6%9E%B6%E5%BC%80%E5%8F%91/","content":"项目初始化npm init -y\n\n安装依赖\ncommander:命令行工具\nprompts:交互式命令行工具\nkolorist:修改控制台输出内容样式\nvalidate-npm-package-name:用于验证npm包名称是否有效\n\n编写脚本文件在package.json中指定项目的可执行文件:\n{ ..., "bin": { "my-cli": "./bin/index.js" }}\n\n在根目录下新建一个bin文件夹,并创建脚本文件index.js:\n#!/usr/bin/env nodeconst { Command } = require('commander')const prompts = require('prompts')const path = require('path')const fs = require('fs-extra')const validateProjectName = require('validate-npm-package-name')const os = require('os')const { cyan, green, magenta, red, blue,} = require('kolorist')const packageJson = require('../package.json')// 可用的模板const templateList = [ { title: cyan('react-app'), value: 'react-app', }, // 其它可选项]async function init() { const program = new Command(packageJson.name) .version(packageJson.version) .argument('<project-directory>') .action(async (name) => { const root = path.resolve(name) const appName = path.basename(root) checkAppName(appName) fs.ensureDirSync(name) try { const response = await prompts( [ { type: () => (isSafeToCreateProjectIn(root, name) ? null : 'confirm'), name: 'overwrite', message: 'Remove existing files and continue?', initial: false, }, { type: (_, { overwrite }) => { if (overwrite === false) { throw new Error(`${red('✖')} Operation cancelled`) } return null }, name: 'overwriteChecker', }, { type: 'select', name: 'template', message: 'Select a template', choices: templateList, }, ], { onCancel: () => { throw new Error(`${red('✖')} Operation cancelled`) }, }, ) const { template, overwrite } = response if (overwrite) { cleanDir(root) } createApp(root, appName, template) } catch (cancelled) { console.log(cancelled.message) } }) .on('--help', () => { }) .parse(process.argv)}/** * 创建应用至指定路径,并且将应用名称等信息与模板中预设的package.json合并 * @param appPath * @param appName * @param template * @returns {Promise<void>} */async function createApp(appPath, appName, template) { const templatePath = path.join(__dirname, `../templates/${template}`) const templateJsonPath = path.join(templatePath, 'template.json') let templateJson = {} if (fs.existsSync(templateJsonPath)) { // eslint-disable-next-line global-require,import/no-dynamic-require templateJson = require(templateJsonPath) } const appPackage = { name: appName, version: '0.1.0', private: true, } const templatePackage = templateJson.package || {} Object.assign(appPackage, templatePackage) fs.writeFileSync( path.join(appPath, 'package.json'), JSON.stringify(appPackage, null, 2) + os.EOL, ) const templateDir = path.join(templatePath, 'template') copyDir(appPath, appName, templateDir).then(() => { console.log('') console.log('Success! Now run: ') console.log('') console.log(` cd ${appName}`) console.log(' npm install') console.log(' npm run dev') })}/** * 校验包名称是否有效 * @param appName */function checkAppName(appName) { const validationResult = validateProjectName(appName) if (!validationResult.validForNewPackages) { console.error( red( `Cannot create a project named ${green( `"${appName}"`, )} because of npm naming restrictions:\\n`, ), ); [ ...(validationResult.errors || []), ...(validationResult.warnings || []), ].forEach((error) => { console.error(red(` * ${error}`)) }) console.error(red('\\nPlease choose a different project name.')) process.exit(1) }}let conflicts = []/** * 判断指定路径下的文件夹是否为空 * @param root * @param name * @returns {boolean} */function isSafeToCreateProjectIn(root, name) { const validFiles = [ '.DS_Store', '.git', '.gitignore', '.idea', 'README.md', 'package.json', 'package-lock.json', 'yarn-lock.json', ] const errorLogFilePatterns = [ 'npm-debug.log', 'yarn-error.log', 'yarn-debug.log', ] const isErrorLog = (file) => errorLogFilePatterns.some((pattern) => file.startsWith(pattern)) conflicts = fs .readdirSync(root) .filter((file) => !validFiles.includes(file)) .filter((file) => !isErrorLog(file)) if (conflicts.length > 0) { console.log( `The directory ${green(name)} contains files that could conflict:`, ) console.log('') conflicts.forEach((file) => { try { const stats = fs.lstatSync(path.join(root, file)) if (stats.isDirectory()) { console.log(` ${blue(`${file}/`)}`) } else { console.log(` ${file}`) } } catch (e) { console.log(` ${file}`) } }) console.log() console.log( 'Either try using a new directory name, or remove the files listed above.', ) console.log() return false } fs.readdirSync(root).forEach((file) => { if (isErrorLog(file)) { fs.removeSync(path.join(root, file)) } }) return true}/** * 拷贝应用模版至指定路径下 * @param appPath * @param appName * @param templateDir * @returns {Promise<unknown>} */function copyDir(appPath, appName, templateDir) { return new Promise((resolve) => { if (fs.existsSync(templateDir)) { fs.copySync(templateDir, appPath) resolve() } else { console.error(`Could not locate supplied template: ${green(templateDir)}`) process.exit(1) } })}/** * 清空指定路径下的所有文件及文件夹 * @param root */function cleanDir(root) { if (!fs.pathExistsSync(root)) { return } fs.readdirSync(root).forEach((file) => { fs.rmSync(path.resolve(root, file), { recursive: true, force: true }) })}init()\n\n创建命令使用commander可以快速构建命令行程序:\n#!/usr/bin/env nodeconst { Command } = require('commander')async function init() { const program = new Command(packageJson.name) \t// 配置版本号信息 .version(packageJson.version) \t// 配置必填参数 .argument('<project-directory>') \t// 调用命令后执行任务 .action(() => { }) \t// 完善更多帮助信息 .on('--help', () => { }) \t// 解析执行命令时传入的参数 .parse(process.argv)}\n\n命令行交互通过使用prompts,可以在命令行中与用户进行交互,获取用户的输入并根据需要执行相应的操作:\nconst response = await prompts( [ { type: 'select', name: 'template', message: 'Select a template', choices: templateList, }, ], { onCancel: () => { throw new Error(`${red('✖')} Operation cancelled`) }, },)const { template } = response\n\n使用模板有两种使用模板的方式,并各有优缺点:\n\n拷贝本地模板\n优点:\n离线使用:用户只要安装脚手架以后,即使在没有网络链接的情况下也能够正常使用脚手架和模版。\n快速启动:创建项目时不需要等待下载模板的过程,可以立即开始项目的开发。\n简单维护:模板和脚手架在同一个版本控制系统中,维护和更新都比较方便。可以通过版本控制系统的标签或分支管理模板的不同版本。\n\n\n缺点:\n更新困难:当需要更新模板时,需要发布新版本的脚手架。用户在升级脚手架时会受到模板更新的影响,无法选择保留原来的模板。\n模板定制性较差:模板与脚手架耦合在一起,定制模板的难度较大。用户想要对模板进行修改时,需要修改脚手架源码。\n\n\n\n\n下载远程模版\n优点:\n实时更新:模板存储在远程Git仓库中,可以随时更新和维护。用户在创建项目时可以获取到最新的模板。\n独立维护:模板和脚手架分离,可以独立维护模板。可以针对不同的项目需求,使用不同的Git分支或标签管理不同版本的模板。\n定制性强:用户可以根据项目需求,对远程模板进行定制化修改,而不需要修改脚手架源码。\n\n\n缺点:\n依赖网络:用户需要有可靠的网络连接,才能下载远程模板。\n下载时间:创建项目时需要从远程Git仓库下载模板,这可能需要一定的时间,特别是在网络较慢的情况下。\n\n\n\n\n\n拷贝本地模板在根目录下创建templates文件夹,用于存放模板:\ntemplates└── react-app-ts ├── template │ ├── commitlint.config.js │ ├── react-app-env.d.ts │ ├── src │ ├── tsconfig.json │ └── webpack └── template.json\n\n将目标模板下的文件以及文件夹拷贝至指定路径下:\nfunction copyDir(appPath, appName, templateDir) { return new Promise((resolve) => { if (fs.existsSync(templateDir)) { fs.copySync(templateDir, appPath) resolve() } else { console.error(`Could not locate supplied template: ${green(templateDir)}`) process.exit(1) } })}\n\n下载远程模版download-git-repo 是一个专门用于从 Git 仓库下载模板的库。并且可以使用ora在命令行界面中显示加载动画和提示信息,以增强用户体验:\nconst download = require('download-git-repo')const ora = require('ora')function downloadTemplate(appPath, appName) { const spinner = ora('初始化项目') spinner.start() spinner.text = `项目${appName}初始化中` spinner.spinner = { interval: 120, frames: ['. ', '.. ', '...', '.. '], } return new Promise((resolve, reject) => { download('direct:https://github.com/xxx.git', appPath, { clone: true }, (err) => { if (err) { spinner.fail('项目初始化失败') reject(err) } else { spinner.succeed('项目初始化成功') resolve() } }) })}\n\n其它用于下载远程模板的Node.js库:got一个通用的 HTTP 请求库,可以用于下载任何远程资源。\n本地调试执行命令npm link即可将脚手架链接到全局node_modules目录下,执行以下命令开始调试:\nmy-cli your-project-directory\n\n\n\n发布登录你的 npm 账号:\nnpm login --registry https://www.npmjs.com\n\n执行发布命令:\nnpm publish\n\n","categories":["前端"],"tags":["cli"]},{"title":"Cordova常见问题","url":"/2018/11/02/cordova/Cordova%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/","content":"启动前黑屏创建styles.xml文件——注意:文件名固定不能变,因为是android特有文件名\nplatforms\\android\\app\\src\\main\\res\\values\\styles.xml\n<resources> <style name="WelcomeStyle" parent="@android:style/Theme.DeviceDefault.NoActionBar"> <item name="android:windowBackground">@drawable/screen</item> <item name="android:windowFullscreen">false</item> </style> <style name="Appwelcome" parent="android:Theme.Translucent.NoTitleBar.Fullscreen"> </style></resources>\n\n\na. 创建一个主题,修改其背景为透明,或者和启动屏图片一致\nb. AndroidManifest.xml文件,把主题改为上述主题。\n\n打开config.xml,添加配置项:\n<platform name="android"> <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application/activity[@android:name='MainActivity']"> <activity android:theme="@style/WelcomeStyle" /> </edit-config></platform>\n\n在widget标签中添加xmlns:android="http://schemas.android.com/apk/res/android"\n<widget xmlns:android="http://schemas.android.com/apk/res/android"> \n\n运行ionic cordova build android,没有错误,能正常生成。此时打开platforms\\android\\app\\src\\main\\AndroidManifest.xml\n详细\n启动页结束短暂白屏在config.xml中添加配置项\n<preference name="SplashScreenDelay" value="10000" /><preference name="ShowSplashScreenSpinner" value="false" /><preference name="SplashMaintainAspectRatio" value="false" /><preference name="SplashShowOnlyFirstTime" value="false" /><preference name="SplashScreenHide" value="true" /><preference name="AutoHideSplashScreen" value="false" /><preference name="FadeSplashScreen" value="false" />\n\nvue项目 main.js 添加 navigator.splashscreen.hide()\n// 延时关闭启动页, 避免短暂白屏setTimeout(() => {\tnavigator.splashscreen.hide()}, 1000)\n\n\n\n","tags":["cordova"]},{"title":"hexo-Anisina 使用心得","url":"/2017/07/04/hexo/hexo-Anisina%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97/","content":"写在开头1.个人博客采用hexo快速搭建,使用主题为Anisina,主题原作者编写的中文使用教程请敲这里,也可以选择其他主题\n2.本文内容主要在于通过分析layout布局模板和config配置文件,更好理解Anisina主题的使用方法\n3.对works.ejs文件做了部分修改,config.yml新增Project Info。详情\nHexo什么是 Hexo?Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。\n安装npm install hexo-cli -g\n\n建站安装 Hexo 完成后,请执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件。\n$ hexo init <folder>$ cd <folder>$ npm install\n\n新建完成后,指定文件夹的目录如下:\n.├── _config.yml\t\t\t#配置文件夹├── package.json\t\t#应用程序的信息├── scaffolds\t\t\t#模板文件夹├── source\t\t\t\t#资源文件夹| ├── _drafts| └── _posts└── themes\t\t\t\t#主题文件夹\n\n常用命令$ hexo init [folder]\t\t\t#新建一个网站$ hexo new [layout] <title>\t\t#新建一篇文章$ hexo g\t\t\t\t\t\t#生成静态文件$ hexo clean\t\t\t\t\t#清空缓存$ hexo server\t\t\t\t\t#运行服务器$ hexo d\t\t\t\t\t\t#部署到git仓库\n\n\nAnisina1.安装git clone https://github.com/Haojen/hexo-theme-Anisina.gitclone`下来后将文件拷贝至`hexo init [folder]/themes\n\n2.修改1.将Anisina文件拷贝到themes文件2.themes: Anisina3.或者直接拷贝 Anisina 文件夹下的 `_config.yml` 替换 hexo 默认的 _config.yml\n\n3.配置文件_config.yml配置文件采用key: value的形式,:后面一定要带空格,否则error。可以拷贝key之后ctrl + f 查找快速修改配置信息。\n# Sitetitle: # your blog title nameauthor: # your nameheader-img: \t# background imagefavicon: \t# website icon# SNS settingsgithub_username: # Id of a social account# Sidebar settingssidebar-about-description: \t# your individual descriptionsidebar-avatar: # your photo# 配置git仓库地址,配置完成后每次只需要执行 hexo d 就能将public文件push到仓库deploy: type: git repo: \t# The repository with you want to upload branch: master # 文章header-img背景图片,url采用'cdn-url' + 'header-img'拼接的方式。cdn-url: http://ot0jk0h4v.bkt.clouddn.com/ # 你的CDN地址# 博文默认图片(如果不设置这一项, 博文标题的图片默认是灰色的)post-default-img: post-default.jpg# 友链, 请务必按以下格式书写friends: [\t{\t\ttitle: "your friend title",\t\thref: "your fiend path"\t},\t{\t\ttitle: "your friend title 2",\t\thref: "your friend path 2"\t}] # 页面nav配置,这里重写了nav.ejs模板menu: Home: / Tags: /tags My Works: /work # my works Project Info\t同样,重写了works.ejs模板project: [ { title: , subTitle: , data: , img_link: , tags: [], direction: , link: /# }]\n\n4.创建一个 Tags 导航页面\n运行命令:hexo new page "Tags" , 这会在博客的 source 目录下生成一个名为 Tags 的文件夹, 里面会有一个 index.md 格式的页面,如果没有请手动创建.\n然后打开 yourblog/source 文件夹 , 找到 Tags/index.md 这个文件, 然后设置在两条的---里面, 指定一个 layout: tags值.注意 key 和 value 之间的空格\n然后运行命令,重新生成博客内容: hexo clean && hexo g , 然后可以运行 hexo serve 在本地查看效果\n\n5.博文运行命令:hexo new post folder,这会在source/_posts\n以下是博文配置\n---layout: posttitle: "Hola 2016"subtitle: "hi, I'm haojen ma"date: 2016-05-26 06:00\t# 博文创建时会自动生成author: "Haojen Ma"header-img: "img/post-default.jpg"cdn: 'header-on'tags:\t- Movies\t- Lifetop: num\t#可将博文置顶,num值越大优先级越高---\n\n创建一条博文hexo new "your-post-name"\n\n创建一条博文的同时,也会创建一个以该博文名命名的文件夹:\n博文标题背景图片\nheader-img: “http://sometest.png“\n\n如果你没有设置的话,会默认使用 _config.yml 下 post-default-img指定的背景图像\n6.创建My Works界面运行命令:hexo new page work,这会在source目录下生成一个work文件夹\n---title: my worksdate: 2017-07-17 17:34:13layout: works---\n\n修改works.ejs模板打开themes/layout/works.ejs文件,重写class="container"标签内代码\n<div class="container"> <section class="row"> <div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 works-area"> <% for(var obj of config.project){ %> <div class="works-item"> <div class="title"> <h3> <%= obj.title %> </h3> <span class="title-date text-muted"> <%= obj.data %> </span> </div> <div class="works-item-img"> <img src="<%= obj.img_link %>"> </div> <div class="works-content"> <% if(obj.tags){ %> <div class="use text-warning"> <% for (var arrayVal in obj.tags ){ %> <span> <%= obj.tags[arrayVal] %> </span> <% } %> </div> <% } %> <% if(obj.subTitle){ %> <p class="subtitle"> <%= obj.subTitle %> </p> <% } %> <% if(obj.direction){ %> <p class="text-muted"> <%= obj.direction %> </p> <% } %> </div> <div class="footer clearfix"> <a class=" btn btn-default" href="<%= obj.link %>" target="_blank"> Open it</a> </div> </div> <% } %> </div> </section> </div>\n\n从上面的ejs模板可以看出,在浏览器渲染数据时,会先查找_config.yml文件中的key为project的数组\nexample:\nproject: [ { title: , subTitle: , data: , img_link: , tags: [], direction: , link: /# } ]\n\n7.博文置顶可能是我技术小白,没有在作者的源码中找到博文置顶的功能,遂自己参考网络资料对node_modules/hexo-generator-index/lib/generator.js进行了修改,具体可参考博文\n","tags":["hexo"]},{"title":"post博文置顶功能","url":"/2017/07/04/hexo/post%E5%8D%9A%E6%96%87%E7%BD%AE%E9%A1%B6%E5%8A%9F%E8%83%BD/","content":"Hexo博客添加文章置顶功能换了主题以后一直很苦恼于无法管理制定文章,Hexo只提供了按发布时间的降序排列,只好参考了网上的资料修改源文件\n原理:在Hexo生成首页HTML时,将top值高的文章排在前面,达到置顶功能。\n修改Hexo文件夹下的node_modules/hexo-generator-index/lib/generator.js,在生成文章之前进行文章top值排序。\n这是修改后的generator.js,直接将代码拷贝下来覆盖源码保存就行\n代码'use strict';var pagination = require('hexo-pagination');module.exports = function(locals){ var config = this.config; var posts = locals.posts; posts.data = posts.data.sort(function(a, b) { if(a.top && b.top) { // 两篇文章top都有定义 if(a.top == b.top) return b.date - a.date; // 若top值一样则按照文章日期降序排 else return b.top - a.top; // 否则按照top值降序排 } else if(a.top && !b.top) { // 以下是只有一篇文章top有定义,那么将有top的排在前面(这里用异或操作居然不行233) return -1; } else if(!a.top && b.top) { return 1; } else return b.date - a.date; // 都没定义按照文章日期降序排 }); var paginationDir = config.pagination_dir || 'page'; return pagination('', posts, { perPage: config.index_generator.per_page, layout: ['index', 'archive'], format: paginationDir + '/%d/', data: { __index: true } });};\n\nexample---title: hexo-Anisina使用心得subtitle: 更新了tag置顶的方法date: 2016-07-16 18:27:47tags: Hexoheader-img: cdn: header-off\ttop: 1\t---\n","tags":["hexo"]},{"title":"奇淫技巧","url":"/2017/09/06/javascript/%E5%A5%87%E6%B7%AB%E6%8A%80%E5%B7%A7/","content":"javaScript 奇淫技巧1.论如何最佳的让两个整数交换数值\n常规办法:\nvar a=1,b=2;a += b;b = a -b;a -= b;\n\nES6:\nvar a=1,b=2;[a,b] = [b,a];\n\n\n2.如何优雅的实现金钱格式化:1234567890 –> 1,234,567,890\n正则魔法:\nvar test1 = '1234567890'var format = test1.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')console.log(format) // 1,234,567,890\n\ntoLocaleString() 方法,把数组转换为本地字符串。\n(1234567890).toLocaleString('en-US');\n\n\n3.ES6 数组去重\n[...new Set([1,"1",1,1,2,3])];\n\n\n4.用最短的代码实现一个长度为n且值都为m的数组\nArray(6).fill(8);\n\n\n5.取出一个数组中的最大值和最小值\nvar numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; var maxInNumbers = Math.max.apply(Math, numbers); var minInNumbers = Math.min.apply(Math, numbers);\n\n\n6.论如何优雅的取随机字符串\nMath.random().toString(16).substring(2) // 13位Math.random().toString(36).substring(2) // 11位\n\n\n7.单行写一个评级组件\n"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);定义一个变量rate是1到5的值var rate = 2; //"★★☆☆☆"\n","categories":["前端"],"tags":["JS"]},{"title":"npm 包发布流程","url":"/2023/03/10/npm/npm%E5%8C%85%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B/","content":"创建你的 npm 账号在发布一个npm包之前,需要准备一个属于你的npm账号。注册地址\n创建 npm 包创建你的包文件夹一个简单的npm包文件夹,应该包含以下部分:\n├── README.md├── lib│ └── index.js└── package.json\n\n关于package.jsonpackage.json是一个npm包中的重要文件,有了package.json文件才能将你的包发布到 npm注册表。你可以将package.json文件添加到你的包中,以方便其他人管理和安装。\n通过以下命令创建package.json:\nnpm init\n\n以下为package.json中包含的一些常见属性:\n{ "name": "my_package", // 包名称 "description": "", // 关于包的描述信息,如果包目录中包含 README.md,将已 README 为准 "version": "1.0.0", // 版本号 "main": "lib/index.js", // 项目入口文件 "files": ["lib"], // 项目中要发布的文件列表 "scripts": { "test": "echo \\"Error: no test specified\\" && exit 1" }, // 可执行的脚本命令 "repository": { "type": "git", "url": "https://github.com/monatheoctocat/my_package.git"}, // 仓库信息 "keywords": [], // 关键字 "author": "", // 作者 "license": "ISC", // 许可证 "bugs": { "url": "https://github.com/monatheoctocat/my_package/issues" }, // 项目的 bug 报告地址 "homepage": "https://github.com/monatheoctocat/my_package", // 项目的主页地址}\n\n关于README.md在项目的根目录下创建README.md作为npm包的自述文件,可以帮助其他人在 npm上找到你的包并在他们的项目中使用你的代码获得良好的体验。该文件可能包含安装、配置和使用包中代码的说明,以及用户可能认为有帮助的任何其他信息。\n你可以创建 README.md 文件并将其添加到包中:\n\n在文本编辑器中,在您的包根目录中,创建一个名为 README.md 的文件\n在该README.md文件中,添加有关您的包的有用信息。\n保存README.md文件。\n\n本地调试将npm包发布到线上进行调试过于繁琐,并且仅为了调试代码而频繁地发布会导致版本号膨胀。所以在正式发布npm包之前,最好在本地进行调试。\n你可以使用 npm link将你的包链接到全局node_modules目录下,之后在将包链接到具体的代码目录下。\n例如:\ncd ~/projects/node-redis # go into the package directorynpm link # creates global linkcd ~/projects/node-bloggy # go into some other package directory.npm link redis # link-install the package\n\n要解除项目与包的链接,只需要执行以下命令:\nnpm unlink redis\n\n发布 npm 包登录 npm 账号\n在登录你的 npm 账号前,请确保切换到官方镜像源:\n\nnpm config set registry https://registry.npmjs.org/\n\n\n登录你的 npm 账号:\n\nnpm login\n\n\n提示你输入用户名,密码和邮箱地址:\n\nnpm notice Log in on https://registry.npmjs.org/Username: yournamePassword: *****Email: (this IS public) youremail\n\n执行发布命令npm publish\n\n更新 npm 包版本当你对已发布的包进行重大更改时,应该更新版本号,以便将更改的范围传达给依赖你代码的其他人。\n你可以使用以下命令更改package.json中的版本号:\nnpm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]\n\n部分不同选项的作用:\n\npatch: 1.0.0 –> 1.0.1\nminor:1.0.0 –> 1.1.0\nmajor: 1.0.0 –> 2.0.0\n\n更多选项或参数可参考npm version\n取消发布包使用官网\n在 npm 的“登录”页面上,输入您的帐户详细信息并单击“登录”。\n\n\n导航到您要取消发布的包的包页面,替换<your-package-name>为您的包的名称: https://www.npmjs.com/package/<your-package-name>\n\n单击设置。\n\n\n在“删除包”下,单击删除包。\n\n\n如果您确定要继续,请输入您的包名称并单击删除包。\n\n\n使用命令行要取消发布整个包,请运行以下命令,替换<package-name>为您的包的名称:\nnpm unpublish <package-name> -f\n\n更多操错可参考https://docs.npmjs.com/unpublishing-packages-from-the-registry\nFAQ登录失败设置官方镜像源,使用npm login登录的时候记得切换成官方镜像源地址:\nnpm config set registry https://registry.npmjs.org/\n\n设置淘宝镜像源:\nnpm config set registry https://registry.npmmirror.com/\n\n查看当前镜像源:\nnpm config get registry\n\n包名被占用这是一个常见问题,因为很多人都发包到 npm 上。有时候很难得到你想要的包名。\n为了解决这个问题,npm 允许发包到一个命名空间下。这意味着可以把包发布到你自己的用户名或者组织名下,因此解决了命名问题。\n要发包到一个命名空间下,你需要选择如下其中一种方式:\n\n手动修改 package.json 中的 name 属性值为 @username/package-name 格式\n运行 npm init –scope=username 而非 npm init\n\n如果你的仓库有命名空间,你需要微调一下 publish 命令:\nnpm publish --access public\n\n","categories":["前端"],"tags":["npm"]},{"title":"vue-cli3.x config","url":"/2019/04/22/vue/vue-cli3-x%E9%85%8D%E7%BD%AE/","content":"介绍\nVue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:\n\n通过 @vue/cli 搭建交互式的项目脚手架。\n通过 @vue/cli + @vue/cli-service-global 快速开始零配置原型开发。\n一个运行时依赖 (@vue/cli-service),该依赖:\n可升级;\n基于 webpack 构建,并带有合理的默认配置;\n可以通过项目内的配置文件进行配置;\n可以通过插件进行扩展。\n\n\n一个丰富的官方插件集合,集成了前端生态中最好的工具。\n一套完全图形化的创建和管理 Vue.js 项目的用户界面。\n\n\n安装installnpm install -g @vue/cli# ORyarn global add @vue/cli\n\nversionvue --version\n\ncreatevue create hello-world\n\nplugins\nInstall\n\n# options ['babel', 'pwd', 'typescript', 'eslint', ...]vue add @vue/options\n\n\nLink\nBabel\nESlint\nTypeScript\nPWA\n…\n\n\n\n配置参考\n传送门\n\nExamplemodule.exports = {\tpublicPath: process.env.NODE_ENV === 'production'\t ? '/production-sub-path/'\t : '/',\t// 是否开启 eslint 语法检查 lintOnSave: process.env.NODE_ENV !== 'production', // 是否使用包含运行时编译器的 Vue 构建版本 \truntimeCompiler: true, \t// 是否需要 source map, 关闭以加速生产环境构建 \tproductionSourceMap: false, \t// 完整选项查看 https://webpack.js.org/configuration/dev-server/ \tdevServer: { \t\thost: '0.0.0.0', \t\thotOnly: true, \t\topen: true, \t\t// 完整选项查看 https://github.com/chimurai/http-proxy-middleware#proxycontext-config \t\tproxy: { \t\t\t'/api': {\t\t target: 'http://127.0.0.1',\t\t // ws: true,\t\t // changeOrigin: true\t\t }, \t\t} \t}, \tcss: { \t\tmodules: false, \t\t// 是否将组件中的 CSS 提取至一个独立的 CSS 文件中, 默认生产环境开启, 开发环境关闭 \t\textract: process.env.NODE_ENV === 'production', \t\t// 是否为 CSS 开启 source map。设置为 true 之后可能会影响构建的性能 \t\tsourceMap: false, \t\t// 向 CSS 相关的 loader 传递选项 \t\tloaderOptions: { \t\t\t// // 给 less-loader 传递选项 \t\t\tless: { \t\t\t\t// @/ 是 src/ 的别名 \t\t// 所以这里假设你有 `src/variables.scss` 这个文件 \t\t\t\tdata: `@import "~@/assets.less";` \t\t\t} \t\t} \t}, pages: {\t index: {\t // page 的入口\t entry: 'src/main.js',\t // 模板来源\t template: 'public/index.html',\t // 在 dist/index.html 的输出\t filename: 'index.html',\t // 当使用 title 选项时,\t // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>\t title: 'Index Page',\t // 在这个页面中包含的块,默认情况下会包含\t // 提取出来的通用 chunk 和 vendor chunk。\t chunks: ['chunk-vendors', 'chunk-common', 'index']\t },\t // 当使用只有入口的字符串格式时,\t // 模板会被推导为 `public/subpage.html`\t // 并且如果找不到的话,就回退到 `public/index.html`。\t // 输出文件名会被推导为 `subpage.html`。\t // subpage: 'src/main.js' \t}}\n\n","categories":["前端"],"tags":["Vue"]}]