pleasestartyourperformance / webpack Goto Github PK
View Code? Open in Web Editor NEWwebpack-技术专栏
webpack-技术专栏
webpack 4.0以前,我们通过extract-text-webpack-plugin插件,把css样式从js文件中提取到单独的css文件中。extract-text-webpack-plugin插件的优缺点:
在webpack4.0出现后使用mini-css-extract-plugin插件来打包css文件。
//安装
yarn add -D mini-css-extract-plugin
这个插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
})
],
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
}
]
}
}
还有个简单的例子
{
entry: {
index: "../src/index.js",
utils: '../src/utils.js',
},
output: {
filename: "[name].bundle.js", // 输出 index.js 和 utils.js
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 创建一个 link 标签
'css-loader', // css-loader 负责解析 CSS 代码, 处理 CSS 中的依赖
],
},
]
}
plugins: [
// 用 MiniCssExtractPlugin 抽离出 css 文件,以 link 标签的形式引入样式文件
new MiniCssExtractPlugin({
filename: 'index.bundle.css' // 输出的 css 文件名为 index.css
}),
]
}
const path = require('path');
{
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, "app/src"),
path.resolve(__dirname, "app/test")
],
exclude: /node_modules/
// exclude: [/node_modules/,/xxx/] 数组写法
}]
}
}
include:表示哪些目录下的.js需要 babel-loader
exclude:表示哪些目录下的.js需要 不需要babel-loader
路径:scripts
generate.js
#!/usr/bin/env node
const path = require('path');
const fs = require('fs-extra');
const inquirer = require('inquirer');
const templatePath = path.join(__dirname, 'template');
const srcPath = path.join(__dirname, '../src');
const comps = require('../components.json');
const contentReplace = (content, data) => {
return content.replace(/__COMPONENT_NAME__/g, data.componentName)
.replace(/__COMPONENT_CLASS_NAME__/g, data.componentClassName)
.replace('__COMPONENT_FILENAME__', data.componentFileName)
.replace('__COMPONENT_TAG_NAME__', data.componentFileName)
.replace('__STORIES_ORDER__', data.storiesOrder)
.replace(/.tpl$/g, '');
}
const fileGen = (srcPath, distPath, data) => {
const files = fs.readdirSync(srcPath);
files.forEach(file => {
const fileContent = fs.readFileSync(path.join(srcPath, file));
let fileString = fileContent.toString();
fileString = contentReplace(fileString, data);
file = contentReplace(file, data);
fs.ensureDirSync(distPath);
fs.writeFileSync(distPath + '/' + file, fileString)
console.log(distPath + '/' + file)
})
};
const componentsPath = path.join(srcPath, 'components');
const storiesPath = path.join(srcPath, 'stories');
const typesPath = path.join(__dirname, '../types');
const indexFilePath = path.join(componentsPath, 'index.ts');
const xinUiDFilePath = path.join(typesPath, 'xin-ui.d.ts');
const stories = fs.readdirSync(storiesPath);
const storiesOrder = stories.filter(s => fs.statSync(path.join(storiesPath, s)).isDirectory()).length;
function gen(inputName) {
if(/^(x|X)in*/i.test(inputName)) {
console.log(`组件: [${inputName}] 不能以 (x|X)in* 开头,程序内会自动补充,换个名字再试试吧!!!`);
process.exit(1)
return;
}
if(Object.keys(comps).length) {
let compKeys = Object.keys(comps);
let _inputName = inputName.replace(/[-_](\w)/g, function (all, letter) {
return letter.toUpperCase();
}).replace(/^(\w)/, function (all, letter) {
return letter.toUpperCase();
});
if(compKeys.includes(`Xin${_inputName}`)) {
console.log(`组件: [Xin${_inputName}] 已存在,请尝试其他名字再试试!!!`);
process.exit(1)
return;
}
}
const data = {
componentName: inputName.replace(/[-_](\w)/g, function (all, letter) {
return letter.toUpperCase();
}).replace(/^(\w)/, function (all, letter) {
return letter.toUpperCase();
}),
componentClassName: inputName,
componentFileName: inputName,
componentsXinName: `xin-${inputName}`,
storiesOrder: storiesOrder
}
const indexFile = fs.readFileSync(indexFilePath);
let indexFileString = indexFile.toString()
indexFileString = indexFileString.replace(
/(import\s+.*\s+from\s+.*\n)(\n+[^import])/,
`$1import Xin${data.componentName} from './xin-${data.componentFileName}/index';\n$2`
).replace(
/(const\s+components\s+=\s+\[.*\n)((.*,\n)+)(.*)(\n\])/,
`$1$2$4,\n Xin${data.componentName}$5`
).replace(
/(export\s+\{.*\n)((.*,\n)+)(.*)(\n\})/,
`$1$2$4,\n Xin${data.componentName}$5`
)
const xinUiDFile = fs.readFileSync(xinUiDFilePath)
let xinUiDFileString = xinUiDFile.toString();
xinUiDFileString = xinUiDFileString.replace(
/(import\s+.*\s+from\s+.*\n)(\n+[^import])/,
`$1import {Xin${data.componentName}} from './components/xin-${data.componentFileName}';\n$2`
).replace(
/(export\s+\{.*\n)((.*,\n)+)(.*)(\n\})/,
`$1$2$4,\n Xin${data.componentName}$5`
)
fileGen(path.join(templatePath, 'components'), path.join(componentsPath, data.componentsXinName), data);
fileGen(path.join(templatePath, 'componentsIndex'), path.join(componentsPath, data.componentsXinName), data);
fileGen(path.join(templatePath, 'stories'), path.join(storiesPath, data.componentFileName), data);
fileGen(path.join(templatePath, 'types'), path.join(typesPath, 'components'), data);
fs.writeFileSync(indexFilePath, indexFileString);
fs.writeFileSync(xinUiDFilePath, xinUiDFileString);
}
const inputName = process.argv[2];
if (!inputName) {
inquirer.prompt([
{
type: 'input',
name: 'componentName',
message: '请输入要创建的组件名称:'
}
]).then(answers => {
if (answers.componentName) {
gen(answers.componentName)
}
})
} else {
gen(inputName)
}
模板文件
tpl文件代码用法
<template>
<div class="xin-__COMPONENT_CLASS_NAME__">
__COMPONENT_NAME__
</div>
</template>
<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
@Component({
name: "xin-__COMPONENT_CLASS_NAME__"
})
export default class Xin__COMPONENT_NAME__ extends Vue {
}
</script>
<style scoped lang="scss">
.xin-__COMPONENT_CLASS_NAME__ {
}
</style>
import {Xin__COMPONENT_NAME__} from '../../components';
import Readme from './__COMPONENT_FILENAME__.md';
export default {
title: '__COMPONENT_NAME__',
component: Xin__COMPONENT_NAME__,
parameters: {
order: __STORIES_ORDER__,
notes: Readme
}
};
export const Default = () => ({
components: {Xin__COMPONENT_NAME__},
template: `
<div class="demo-__COMPONENT_CLASS_NAME__">
<xin-__COMPONENT_TAG_NAME__ />
</div>
`
});
Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/。
如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.my-app.com/my-app/ 则设置 publicPath 为 /my-app/
这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统
当运行 vue-cli-service build 时生成的生产环境构建文件的目录。注意目标目录在构建之前会被清除
放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
从生成的资源覆写 filename 或 chunkFilename 时,assetsDir 会被忽略。
开始通过npm init 创建package.json的时候就有⼤量与⽤户的交互(当然也可以通过参数来忽略输⼊);⽽现在⼤多数⼯程都是通过脚⼿架
来创建的,使⽤脚⼿架的时候最明显的就是与命令⾏的交互,如果想⾃⼰做⼀个脚⼿架或者在某些时候要与⽤户进⾏交互,这个时候就不得
不提到inquirer.js了。
介绍
由于交互的问题种类不同,inquirer为每个问题提供很多参数:
type:表⽰提问的类型,包括:input, confirm, list, rawlist, expand, checkbox, password, editor;
name: 存储当前问题回答的变量;
message:问题的描述;
default:默认值;
choices:列表选项,在某些type下可⽤,并且包含⼀个分隔符(separator);
validate:对⽤户的回答进⾏校验;
filter:对⽤户的回答进⾏过滤处理,返回处理后的值;
transformer:对⽤户回答的显⽰效果进⾏处理(如:修改回答的字体或背景颜⾊),但不会影响最终的答案的内容;
when:根据前⾯问题的回答,判断当前问题是否需要被回答;
pageSize:修改某些type类型下的渲染⾏数;
prefix:修改message默认前缀;
suffix:修改message默认后缀。
语法结构
const inquirer = require('inquirer');
const promptList = [
// 具体交互内容
];
inquirer.prompt(promptList).then(answers => {
console.log(answers); // 返回的结果
})
const {getPlugins} = require('./utils/getPlugins');
const {getEntries} = require('./utils/getEntries');
const {getLoaders} = require('./utils/getLoaders');
const {getAlias} = require('./utils/getAlias');
const path = require('path');
module.exports = {
entry: getEntries(),//注意这里------------------------------
output: {
path: path.join(__dirname, '../dist'),
},
resolve: {
extensions: ['.js', '.ts', '.tsx', '.less', '.css'],
alias: getAlias()
},
stats: 'errors-only',
module: {
rules: getLoaders()
},
optimization: {
splitChunks: {
chunks: 'all',
name: 'chunk'
}
},
plugins: getPlugins()
};
const resolve = require('./index').resolve;
function getEntries() {
return {
bundle: [
resolve('./src/old-pages/js/tags-dep.js'),
resolve('./src/old-pages/js/router.js'),
resolve('./src/old-pages/js/boot.js'),
resolve('./thirdsrc/froala/js/froala_editor.js'),
resolve('./thirdsrc/froala/js/plugins/align.min.js'),
resolve('./thirdsrc/froala/js/plugins/colors.min.js'),
resolve('./thirdsrc/froala/js/plugins/draggable.min.js'),
resolve('./thirdsrc/froala/js/plugins/font_size.min.js'),
resolve('./thirdsrc/froala/js/plugins/font_family.min.js'),
resolve('./thirdsrc/froala/js/plugins/fullscreen.min.js'),
resolve('./thirdsrc/froala/js/plugins/image.js'),
resolve('./thirdsrc/froala/js/plugins/image_manager.min.js'),
resolve('./thirdsrc/froala/js/plugins/line_breaker.min.js'),
resolve('./thirdsrc/froala/js/plugins/link.js'),
resolve('./thirdsrc/froala/js/plugins/lists.min.js'),
resolve('./thirdsrc/froala/js/plugins/paragraph_format.min.js'),
resolve('./thirdsrc/froala/js/plugins/table.min.js'),
resolve('./thirdsrc/froala/js/plugins/url.min.js'),
resolve('./thirdsrc/froala/js/plugins/word_paste.js'),
resolve('./thirdsrc/froala/js/languages/zh_cn.js'),
]
};
}
exports.getEntries = getEntries;
/* eslint-disable */
/*
* 数组方法扩展
*/
if (![].indexOf) {
Array.prototype.indexOf = function(val) {
for (var i = 0; i < this.length; i++) {
if (this[i] == val) return i;
}
return -1;
};
}
Array.prototype.remove = function(val) {
var index = this.indexOf(val);
if (index > -1) {
this.splice(index, 1);
}
};
Array.prototype.removeBy = function(key, val) {
for (var i = 0; i < this.length; i++) {
if (Object.prototype.toString.call(this[i]) === '[object Object]') {
if (this[i][key] === val) {
this.splice(i, 1);
}
}
}
};
Array.prototype.unique = function() {
var res = [];
var json = {};
for (var i = 0; i < this.length; i++) {
if (!json[this[i]]) {
res.push(this[i]);
json[this[i]] = 1;
}
}
return res;
};
Array.prototype.clone = function() {
return [].concat(this);
};
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
压缩代码。删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用cssnano(css-loader?minimize)来压缩css
利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output参数和各loader的publicPath参数来修改资源路径
删除死代码(Tree Shaking)。将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数--optimize-minimize来实现
提取公共代码。
在vue中我们经常使用:
看上去非常的不美观而且还容易出错
那么在webpack中可以加入
链式操作:
config
.resolve
.alias
.set('@', resolve('src'))
.set('ts-web', 'hebei-web')
.set('static', resolve('public/static'));
原文:https://blog.csdn.net/u013025674/article/details/87775913
分析资源大小
分析每个步骤花费的时间
优化工具
可以看到,启用这个插件后,loader不占用1s编译时间。因为上次所有的编译内容都被缓存了,新的编译只需要做增量编译即可,不需要重复编译。
npm install --save-dev hard-source-webpack-plugin
# or
yarn add --dev hard-source-webpack-plugin
// webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
context: // ...
entry: // ...
output: // ...
plugins: [
new HardSourceWebpackPlugin()
]
}
HardSourceWebpackPlugin 和 speed-measure-webpack-plugin 不能一起使用
https://juejin.im/post/6887863430510968839?utm_source=gold_browser_extension
构建触发器配置,需要勾选“build when a change is pushed to gitlab. GitLab CI Service URL:http://10.11.3.26:8080/project/test”该项(注意:只有jenkins安装了gitlab hook plugin插件后,才有该项,不安装是没有该选项的)
可以选择这两项
Add timestamps to the Console Output:为控制台添加时间戳
Color ANSI Console Output:彩色控制台
选择执行shell
示例
问题:webpack打包时已经进行gzip压缩了,那为什么还要再次开启nginx的gzip压缩呢?
nginx分为实时gzip和静态gzip, 所谓实时gzip就是无论你的静态资源有没有压缩,我都给你使用gzip压缩一次,所谓静态gzip,就是当你请求某个静态资源时,我先找下该静态资源有没有对应的gz文件,如果有,那nginx就直接使用gz文件,而不再进行实时gzip压缩, 从而减少了nginx对cpu的使用,加快了响应速度. 不过要使用静态gzip必须要先启用nginx的gzip_static 模块.
1.1. mode/–mode参数
新增了mode/--mode参数来表示是开发还是生产(development/production)
production 侧重于打包后的文件大小,development侧重于goujiansud
1.2. 移除loaders,必须使用rules(在3版本的时候loaders和rules 是共存的但是到4的时候只允许使用rules)
1.3. 移除了CommonsChunkPlugin (提取公共代码),用optimization.splitChunks和optimization.runtimeChunk来代替
1.4. 支持es6的方式导入JSON文件,并且可以过滤无用的代码
let jsonData = require('./data.json')
import jsonData from './data.json'
import { first } from './data.json' // 打包时只会把first相关的打进去
1.5. 升级happypack插件(happypack可以进行多线程加速打包)
1.6. ExtractTextWebpackPlugin调整,建议选用新的CSS文件提取kiii插件mini-css-extract-plugin,production模式,增加 minimizer
2.1. loader是使wenbpack拥有加载和解析非js文件的能力
2.2. plugin 可以扩展webpack的功能,使得webpack更加灵活。可以在构建的过程中通过webpack的api改变输出的结果
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个Task
,并合理控制所有Task
的调用关系
webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
compress:一切服务都启用gzip 压缩
open:true启用“打开”后,开发服务器将打开浏览器。
changeOrigin: true,将主机头的来源更改为目标URL
pathRewrite:重写cookie头路径
devServer: {
compress: true,
open: true,
proxy: {
'/api': {
target: 'http://39.99.148.210:1001',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
},
config.devServer
.compress(true)
.open(true)
.proxy({
'/api': {
target: 'http://39.99.148.210:1001',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
})
源码连接:https://github.com/chimurai/http-proxy-middleware#options
webpack文档:https://www.webpackjs.com/configuration/dev-server/#devserver-proxy
chainWebpack: (config) => {
//@代表外面的src哦
config
.resolve
.alias
.set('@', resolve('src'))
.set('static', resolve('public/static'));
config
.plugin('gzip')
.use(CompressionWebpackPlugin, [{
algorithm: 'gzip',
test: new RegExp(
'\\.(' + ['js', 'css'].join('|') +
')$'
),
threshold: 1024,
minRatio: 0.8
}])
config.devServer
.compress(true)
.open(true)
.proxy({
'/api': {
target: 'http://39.99.148.210:1001',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
})
}
devServer: {
compress: true,
open: false, //启动项目自动打开浏览器
proxy: { //代理
'/api': {
target: 'http://192.168.0.37:3001',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
},
npm install --save-dev css-loader style-loader
//sass-loader依赖于node-sass,所以还要安装node-sass
//postcss-loader autoprefixer postcss 处理浏览器兼容
npm install --save-dev postcss-loader autoprefixer postcss
{
test:/\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
'postcss-loader'
]
}),
}
首先安装
$ npm i clean-webpack-plugin --save-dev
然后
plugins:[new CleanWebpackPlugin()],
/**
* 参考文档
* 【eslint英文文档】https://eslint.org/docs/user-guide/configuring
* 【eslint中文文档】http://eslint.cn/docs/rules/
*/
/**
* eslint有三种使用方式
* 【1】js代码中通过注释的方式使用
* 【2】通过webpack的eslintConfig字段设置,eslint会自动搜索项目的package.json文件中的配置
* 【3】通过配置文件的方式使用,配置文件有多种文件方式,如JavaScript、JSON 或者 YAML等
*/
/**
* 文件忽略
* 【】让eslint跳过特定文件的检测
* 【】通过当前工作目录下 「.eslintignore」 文件进行设置
* 其使用的是Glob路径书写方式,与「.gitignore」的使用方法相同
* 【】也可以在 package.json 文件中,通过 eslintIgnore 参数进行设置
*/
/**
* 文件内局部设置
* 【】eslint可以具体文件中设置特定代码的规则,常用于跳过某条语句的检测。
* 【】注销全部规则,在代码前新建一行,添加注销 /* eslint-disable *\/ 。如果没有恢复设置的语句,则下列全部代码都会跳过检测。
* 【】恢复eslint,在代码前新建一行,添加注销 /* eslint-enable *\/
* 【】指定忽略的规则,/* eslint-disable no-alert, no-console *\/
* 【】在特定行禁用,// eslint-disable-line
* 【】在下一行禁用,// eslint-disable-next-line
*/
module.exports = {
/**
* 根目录标识
* http://eslint.cn/docs/user-guide/configuring#using-configuration-files
* http://eslint.cn/docs/user-guide/configuring#configuration-cascading-and-hierarchy
* 【】标识当前配置文件为最底层的文件,无需往更上一级的文件目录中进行搜索
* 【】默认eslint的配置文件搜索方式是,从目标文件夹进行搜索,遍历内部每一个文件夹,找到配置文件并层叠使用。再跳出本项目,往祖先文件夹进行遍历
* 【】注意「~/.eslintrc」的意义,「~」是指linux上的家目录,「~/.eslintrc」是指家目录下的eslint配置文件,用于私人开发者,用于整个电脑全局约束的。这个配置通过本配置项root去设置,设置了root,eslint检测时将不会再往上搜索
* 【】eslint的生效规则是就近使用,越近的配置项优先级越高,覆盖其他配置项。如一个项目中,可以在不同文件夹中都添加配置文件,这些规则将重叠组合生效
*/
root: true, // 标识当前配置文件为eslint的根配置文件,让其停止在父级目录中继续寻找。
/**
* 解析器
* http://eslint.cn/docs/user-guide/configuring#specifying-parser
* 【】ESLint 默认使用Espree作为其解析器
* 【】解析器必须是本地安装的一个 npm 模块。即必须按照在本地的node_module中
* 【】解析器是用于解析js代码的,怎么去理解每一个表达式,有点C++中编译器的概念,会对js进行一些语法分析,语义分析什么的,才能判断语句符不符合规范。而不是通过简单的字符串对比。
* 【】解析器有很多,但兼容eslint的解析器有以下几个
* Espree:默认解析器,一个从Esprima中分离出来的解析器,做了一些优化
* Esprima:js标准解析器
* Babel-ESLint: 一个对Babel解析器的包装,babel本身也是js解析器的一种(不然怎么能转化为兼容性代码呢?首先需要进行js解析,才能转化)。如果我们的代码需要经过babel转化,则对应使用这个解析器
* typescript-eslint-parser(实验) - 一个把 TypeScript 转换为 ESTree 兼容格式的解析器
* 【】但是通常在vue项目中,并不会写在 parser 字段中,而是写在 parserOptions -> parser。具体原因在 parserOptions 一栏中介绍
*/
// parser: 'babel-eslint',
/**
* 解析器配置项
* http://eslint.cn/docs/user-guide/configuring#specifying-parser-options
* 【】这里设置的配置项将会传递到解析器中,被解析器获取到,进行一定的处理。具体被利用到,要看解析器的源码有没有对其进行利用。这里仅仅做了参数定义,做了规定,告诉解析器的开发者可能有这些参数
* 【】配置项目有:
* "sourceType": "module", // 指定JS代码来源的类型,script(script标签引入?) | module(es6的module模块),默认为script。为什么vue的会使用script呢?因为vue是通过babel-loader编译的,而babel编译后的代码就是script方式
* "ecmaVersion": 6, // 支持的ES语法版本,默认为5。注意只是语法,不包括ES的全局变量。全局变量需要在env选项中进行定义
* "ecmaFeatures": { // Features是特征的意思,这里用于指定要使用其他那些语言对象
"experimentalObjectRestSpread": true, //启用对对象的扩展
"jsx": true, //启用jsx语法
"globalReturn":true, //允许return在全局使用
"impliedStrict":true //启用严格校验模式
}
*/
parserOptions: {
/**
* 这里出现 parser 的原因
* 【】首先明确一点,官方说明中,parserOptions的配置参数是不包括 parser 的
* 【】这里的写 parser 是 eslint-plugin-vue 的要求,是 eslint-plugin-vue 的自定义参数
* 【】根据官方文档,eslint-plugin-vue 插件依赖 「vue-eslint-parser」解析器。「vue-eslint-parser」解析器,只解析 .vue 中html部分的内容,不会检测<script>中的JS内容。
* 【】由于解析器只有一个,用了「vue-eslint-parser」就不能用「babel-eslint」。所以「vue-eslint-parser」的做法是,在解析器选项中,再传入一个解析器选项parser。从而在内部处理「babel-eslint」,检测<script>中的js代码
* 【】所以这里出现了 parser
* 【】相关文档地址,https://vuejs.github.io/eslint-plugin-vue/user-guide/#usage
*/
parser: 'babel-eslint',
},
/**
* 运行环境
* http://eslint.cn/docs/user-guide/configuring#specifying-environments
* 【】一个环境定义了一组预定义的全局变量
* 【】获得了特定环境的全局定义,就不会认为是开发定义的,跳过对其的定义检测。否则会被认为改变量未定义
* 【】常见的运行环境有以下这些,更多的可查看官网
* browser - 浏览器环境中的全局变量。
* node - Node.js 全局变量和 Node.js 作用域。
* es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
* amd - 将 require() 和 define() 定义为像 amd 一样的全局变量。
* commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。
* jquery - jQuery 全局变量。
* mongo - MongoDB 全局变量。
* worker - Web Workers 全局变量。
* serviceworker - Service Worker 全局变量。
*/
env: {
browser: true, // 浏览器环境
},
/**
* 全局变量
* http://eslint.cn/docs/user-guide/configuring#specifying-globals
* 【】定义额外的全局,开发者自定义的全局变量,让其跳过no-undef 规则
* 【】key值就是额外添加的全局变量
* 【】value值用于标识该变量能否被重写,类似于const的作用。true为允许变量被重写
* 【】注意:要启用no-global-assign规则来禁止对只读的全局变量进行修改。
*/
globals: {
// gTool: true, // 例如定义gTool这个全局变量,且这个变量可以被重写
},
/**
* 插件
* http://eslint.cn/docs/user-guide/configuring#configuring-plugins
* 【】插件同样需要在node_module中下载
* 【】注意插件名忽略了「eslint-plugin-」前缀,所以在package.json中,对应的项目名是「eslint-plugin-vue」
* 【】插件的作用类似于解析器,用以扩展解析器的功能,用于检测非常规的js代码。也可能会新增一些特定的规则。
* 【】如 eslint-plugin-vue,是为了帮助我们检测.vue文件中 <template> 和 <script> 中的js代码
*/
plugins: ['vue'],
/**
* 规则继承
* http://eslint.cn/docs/user-guide/configuring#extending-configuration-files
*【】可继承的方式有以下几种
*【】eslint内置推荐规则,就只有一个,即「eslint:recommended」
*【】可共享的配置, 是一个 npm 包,它输出一个配置对象。即通过npm安装到node_module中
* 可共享的配置可以省略包名的前缀 eslint-config-,即实际设置安装的包名是 eslint-config-airbnb-base
*【】从插件中获取的规则,书写规则为 「plugin:插件包名/配置名」,其中插件报名也是可以忽略「eslint-plugin-」前缀。如'plugin:vue/essential'
*【】从配置文件中继承,即继承另外的一个配置文件,如'./node_modules/coding-standard/eslintDefaults.js'
*/
extends: [
/**
* vue 的额外添加的规则是 v-if, v-else 等指令检测
*/
'plugin:vue/essential', // 额外添加的规则可查看 https://vuejs.github.io/eslint-plugin-vue/rules/
/**
* 「airbnb,爱彼迎」
* 【】有两种eslint规范,一种是自带了react插件的「eslint-config-airbnb」,一种是基础款「eslint-config-airbnb-base」,
* 【】airbnb-base 包括了ES6的语法检测,需要依赖 「eslint-plugin-import」
* 【】所以在使用airbnb-base时,需要用npm额外下载 eslint-plugin-import
* 【】所以eslint实际上已经因为 airbnb-base 基础配置项目,添加上了 eslint-plugin-import 插件配置
* 【】所以在setting和rules里,都有 'import/xxx' 项目,这里修改的就是 eslint-plugin-import 配置
*/
// 'airbnb-base',
],
/**
* 规则共享参数
* http://eslint.cn/docs/user-guide/configuring#adding-shared-settings
* 【】提供给具体规则项,每个参数值,每个规则项都会被注入该变量,但对应规则而言,有没有用,就看各个规则的设置了,就好比 parserOptions,解析器用不用它就不知道了。这里只是提供这个方法
* 【】不用怀疑,经源码验证,这就是传递给每个规则项的,会当做参数传递过去,但用不用,就是具体规则的事情
*/
settings: {
/**
*
* 注意,「import/resolver」并不是eslint规则项,与rules中的「import/extensions」不同。它不是规则项
* 这里只是一个参数名,叫「import/resolver」,会传递给每个规则项。
* settings并没有具体的书写规则,「import/」只是import模块自己起的名字,原则上,它直接命名为「resolver」也可以,加上「import」只是为了更好地区分。不是强制设置的。
* 因为「import」插件很多规则项都用的这个配置项,所以并没有通过rules设置,而是通过settings共享
* 具体使用方法可参考https://github.com/benmosher/eslint-plugin-import
*/
'import/resolver': {
/**
* 这里传入webpack并不是import插件能识别webpack,而且通过npm安装了「eslint-import-resolver-webpack」,
* 「import」插件通过「eslint-import-resolver-」+「webpack」找到该插件并使用,就能解析webpack配置项。使用里面的参数。
* 主要是使用以下这些参数,共享给import规则,让其正确识别import路径
* extensions: ['.js', '.vue', '.json'],
* alias: {
* 'vue$': 'vue/dist/vue.esm.js',
* '@': resolve('src'),
* 'static': resolve('static')
* }
*/
webpack: {
config: 'build/webpack.base.conf.js'
}
}
},
/**
* 针对特定文件的配置
* 【】可以通过overrides对特定文件进行特定的eslint检测
* 【】特定文件的路径书写使用Glob格式,一个类似正则的路径规则,可以匹配不同的文件
* 【】配置几乎与 ESLint 的其他配置相同。覆盖块可以包含常规配置中的除了 extends、overrides 和 root 之外的其他任何有效配置选项,
*/
// overrides: [
// {
// 'files': ['bin/*.js', 'lib/*.js'],
// 'excludedFiles': '*.test.js',
// 'rules': {
// 'quotes': [2, 'single']
// }
// }
// ],
/**
* 自定义规则
* http://eslint.cn/docs/user-guide/configuring#configuring-rules
* 【】基本使用方式
* "off" 或者0 关闭规则
* "warn" 或者1 将规则打开为警告(不影响退出代码)
* "error" 或者2 将规则打开为错误(触发时退出代码为1)
* 如:'no-restricted-syntax': 0, // 表示关闭该规则
* 【】如果某项规则,有额外的选项,可以通过数组进行传递,而数组的第一位必须是错误级别。如0,1,2
* 如 'semi': ['error', 'never'], never就是额外的配置项
*/
rules: {
/**
* 具体规则
* 【】具体的规则太多,就不做介绍了,有兴趣的同学可以上eslint官网查
* 【】注意 xxx/aaa 这些规则是 xxx 插件自定的规则,在eslint官网是查不到的。需要到相应的插件官网中查阅
* 【】如 import/extensions,这是「eslint-plugin-import」自定义的规则,需要到其官网查看 https://github.com/benmosher/eslint-plugin-import
*/
/**
* 逻辑错误及最佳实践的规则
*/
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, // 打包时禁止debugger
'no-console': process.env.NODE_ENV === 'production' ? 2 : 0, // 打包时禁止console
'no-alert': process.env.NODE_ENV === 'production' ? 2 : 0, // 打包时禁止console
"for-direction": 2, // 禁止for无限循环
"no-compare-neg-zero": 2, // 禁止与-0进行比较
'no-cond-assign': 2, // 禁止条件语句中出现赋值语句
"no-control-regex": 2, // 在 ASCII 中,0-31 范围内的控制字符是特殊的、不可见的字符。这些字符很少被用在 JavaScript 字符串中,所以一个正则表达式如果包含这些字符的,很有可能一个错误。
"no-dupe-args": 2, // 禁止在函数定义或表达中出现重名参数
"no-dupe-keys": 2, // 禁止在对象字面量中出现重复的键
"no-duplicate-case": 2, // 禁止重复 case 标签
"no-empty": 2, // 禁止空块语句
"no-empty-character-class": 2, // 禁止在正则表达式中出现空字符集
"no-ex-assign": 2, // 禁止对 catch 子句中的异常重新赋值。因为catch出来的都是错误信息,不需要重新赋值
"no-extra-boolean-cast": 2, // 禁止不必要的布尔类型转换,如 !!true
"no-extra-semi": 2, // 禁用不必要的分号
"no-inner-declarations": 2, // ??? 禁止在嵌套的语句块中出现变量
"no-regex-spaces": 2, // 禁止正则表达式字面量中出现多个空格
"no-obj-calls": 2, // 禁止将全局对象当作函数进行调用
"no-prototype-builtins": 2, // ??? 禁止直接在对象实例上调用 Object.prototype 的一些方法。
"no-template-curly-in-string": 2, // 禁止在常规字符串中出现模板字面量占位符语法
"semi": [2, 'never'], // ??? 强制是否使用分号。
"no-unexpected-multiline": 2, // 禁止使用令人困惑的多行表达式
"no-unreachable": 2, // 禁止在 return、throw、continue 和 break 语句后出现不可达代码
"use-isnan": 2, // 要求调用 isNaN()检查 NaN
"no-unsafe-negation": 2, // 禁止对关系运算符的左操作数使用否定操作符
"valid-jsdoc": 2, // 强制使用有效的 JSDoc 注释
"valid-typeof": 2, // 强制 typeof 表达式与有效的字符串进行比较
"array-callback-return": 2, // 强制数组方法的回调函数中有 return 语句
"block-scoped-var": 2, // 把 var 语句看作是在块级作用域范围之内
"complexity": [1, 6], // 添加复杂度
"curly": 2, // ??? 要求遵循大括号约定
"default-case": 1, // 要求 Switch 语句中有 Default 分支
"dot-location": [2, 'property'], // 强制在点号之前换行
"dot-notation": 2, // 点号和字面量,优先使用点号
"eqeqeq": [2, 'smart'], // ??? 要求使用 === 和 !==
"guard-for-in": 2, // ??? 需要约束 for-in
"no-caller": 2, // 禁用 caller 或 callee
"no-empty-function": 2, // 禁止出现空函数
"no-empty-pattern": 2, // 禁止使用空解构模式
"no-eval": 2, // 禁用 eval()
"no-global-assign": 2, // 禁止对原生对象或只读的全局对象进行赋值
"no-floating-decimal": 2, // ?? 禁止浮点小数
"no-fallthrough": 2, // 禁止 case 语句落空
"no-labels": 2, // 禁用标签语句
"no-extra-label": 2, // 禁用不必要的标签
"no-extra-bind": 2, // 禁止不必要的函数绑定
"no-iterator": 2, // 禁用迭代器
"no-lone-blocks": 2, // 禁用不必要的嵌套块
"no-loop-func": 2, // 禁止循环中存在函数
"no-magic-numbers": [2, {
ignoreArrayIndexes: true,
ignore: [-1, 0, 1, 2],
}], // 禁止使用魔术数字,魔术数字是在代码中多次出现的没有明确含义的数字。它最好由命名常量取代。
"no-multi-spaces": 2, // 禁止出现多个空格
"no-multi-str": 2, // 禁止多行字符串
"no-new": 2, // 禁止在不保存实例的情况下使用new
"no-new-func": 2, // 禁用Function构造函数
"no-new-wrappers": 2, // 禁止原始包装实例
"no-octal": 2, // 禁用八进制字面量
"no-octal-escape": 2, // 禁止在字符串字面量中使用八进制转义序列
"no-param-reassign": 2, // ??? 禁止对函数参数再赋值
"no-proto": 2, // 禁用__proto__,改用 getPrototypeOf 方法替代 __proto__。
"no-redeclare": 2, // 禁止重新声明变量
"no-return-assign": 2, // 禁止在返回语句中赋值
"no-return-await": 2, // 禁用不必要的 return await
"no-script-url": 2, // 禁用 Script URL
"no-self-assign": 2, // 禁止自身赋值
"no-sequences": 2, // ??? 不允许使用逗号操作符
"no-throw-literal": 2, // 限制可以被抛出的异常
"no-unmodified-loop-condition": 2, // 禁用一成不变的循环条件
"no-useless-call": 2, // 禁用不必要的 .call() 和 .apply()
"no-useless-concat": 2, // 禁止没有必要的字符拼接
"no-useless-escape": 2, // 禁用不必要的转义
"no-useless-return": 2, // 禁止多余的 return 语句
"no-void": 2, // 禁止使用void操作符
"no-with": 2, // 禁用 with 语句
"prefer-promise-reject-errors": 1, // ??? 要求使用 Error 对象作为 Promise 拒绝的原因
"radix": 1, // 要求必须有基数
"require-await": 2, // 禁止使用不带 await 表达式的 async 函数
"vars-on-top": 2, // 要求将变量声明放在它们作用域的顶部
"wrap-iife": [2, 'inside'], // 需要把立即执行的函数包裹起来
"strict": [2, 'global'], // 要求或禁止使用严格模式指令
/**
* 变量相关的规则
*/
"init-declarations": 2, // ??? 强制或禁止变量声明语句中初始化
"no-delete-var": 2, // 禁止删除变量
"no-shadow": 2, // 禁止变量声明覆盖外层作用域的变量
"no-shadow-restricted-names": 2, // 关键字不能被遮蔽
"no-undef": 2, // 禁用未声明的变量
"no-unused-vars": 1, // ??? 禁止未使用过的变量
"no-use-before-define": 2, // 禁止定义前使用
// 代码风格
"array-bracket-newline": [2, 'consistent'], // 在数组开括号后和闭括号前强制换行
"array-bracket-spacing": 2, // 强制在括号内前后使用空格
"array-element-newline": [2, { multiline: true }], // ??? 强制数组元素间出现换行
"block-spacing": 2, // 强制在代码块中开括号前和闭括号后有空格
"brace-style": 2, // 大括号风格要求
"camelcase": 2, // 要求使用骆驼拼写法
"comma-dangle": [2, 'always-multiline'], // 要求或禁止使用拖尾逗号
"comma-spacing": 2, // 强制在逗号周围使用空格
"comma-style": 2, // 逗号风格
"computed-property-spacing": 2, // 禁止或强制在计算属性中使用空格
"consistent-this": [2, 'self'], // ??? 要求一致的 This
"eol-last": [1, 'always'], // ??? 要求或禁止文件末尾保留一行空行
"func-call-spacing": 2, // 要求或禁止在函数标识符和其调用之间有空格
"func-style": [2, 'declaration'], // ??? 强制 function 声明或表达式的一致性
"function-paren-newline": [1, 'multiline'], // 强制在函数括号内使用一致的换行
"indent": [2, 2], // 强制使用一致的缩进
"jsx-quotes": 2, // 强制在 JSX 属性中一致地使用双引号或单引号
"key-spacing": 2, // 强制在对象字面量的键和值之间使用一致的空格
"keyword-spacing": 2, // 强制关键字周围空格的一致性
"linebreak-style": 2, // 强制使用一致的换行符风格,用\n,不用\r\n
"lines-around-comment": 2, // 强制注释周围有空行
"lines-between-class-members": 2, // 要求在类成员之间出现空行
"max-depth": 2, // 强制块语句的最大可嵌套深度
"max-len": [2, { // 强制行的最大长度
"code": 100,
"tabWidth": 4,
"ignoreUrls": true,
"ignoreTrailingComments": true,
"ignoreTemplateLiterals": true,
}], //
"max-lines": [2, 1000], // ??? 强制文件的最大行数
"max-nested-callbacks": [2, 5], // 强制回调函数最大嵌套深度
"max-statements-per-line": 2, // 强制每一行中所允许的最大语句数量
"multiline-comment-style": 1, // 强制对多行注释使用特定风格
"new-cap": 2, // 要求构造函数首字母大写
"new-parens": 2, // 要求调用无参构造函数时带括号
"newline-per-chained-call": 2, // 要求方法链中每个调用都有一个换行符
"no-bitwise": 2, // 禁止使用按位操作符
"no-inline-comments": 0, // ??? 禁止使用内联注释
"no-lonely-if": 2, // 禁止 if 语句作为唯一语句出现在 else 语句块中
"no-mixed-spaces-and-tabs": 2, // 禁止使用 空格 和 tab 混合缩进
"no-multiple-empty-lines": 1, // ??? 不允许多个空行
"no-negated-condition": 2, // 禁用否定表达式
"no-nested-ternary": 2, // 禁止使用嵌套的三元表达式
"no-new-object": 2, // 禁止使用 Object 构造函数
"no-trailing-spaces": 2, // 禁用行尾空白
"no-underscore-dangle": 2, // 禁止标识符中有悬空下划线
"quotes": [2, 'single'], // 强制使用一致的单引号
"quote-props": [2, 'as-needed'], // ??? 要求对象字面量属性名称使用引号
"operator-linebreak": [2, 'before'], // 强制操作符使用一致的换行符风格
"one-var": [2, 'never'], // ??? 强制函数中的变量在一起声明或分开声明
"object-property-newline": 1, // ??? 强制将对象的属性放在不同的行上
"object-curly-spacing": [2, 'always'], // 强制在花括号中使用一致的空格
"object-curly-newline": [1, { // ??? 对象属性换行
multiline: true,
}], //
"no-whitespace-before-property": 2, // 禁止属性前有空白
"no-unneeded-ternary": 2, // 禁止可以表达为更简单结构的三元操作符
"semi-spacing": 2, // 强制分号前后有空格
"semi-style": 2, // 分号风格
"space-before-blocks": [2, 'always'], // 禁止语句块之前的空格
"space-before-function-paren": [2, 'never'], // 禁止函数圆括号之前有一个空格
"space-in-parens": 2, // 禁止或强制圆括号内的空格
"space-infix-ops": 2, // 要求中缀操作符周围有空格
"space-unary-ops": 2, // 禁止在一元操作符之前或之后存在空格
"spaced-comment": 2, // 要求在注释前有空白
"switch-colon-spacing": 2, // 强制在 switch 的冒号左右有空格
"template-tag-spacing": 2, // 要求在模板标记和它们的字面量之间有空格
/**
* ES6相关规则
*/
"arrow-parens": [2, 'as-needed'], // 要求箭头函数的参数使用圆括号
"arrow-body-style": 2, // 要求箭头函数体使用大括号
"arrow-spacing": 2, // 要求箭头函数的箭头之前或之后有空格
"generator-star-spacing": 2, // ??? 强制 generator 函数中 * 号周围有空格
"no-class-assign": 2, // 不允许修改类声明的变量
"no-confusing-arrow": 2, // 禁止在可能与比较操作符相混淆的地方使用箭头函数
"no-const-assign": 2, // 不允许改变用const声明的变量
"no-dupe-class-members": 2, // 不允许类成员中有重复的名称
"no-duplicate-imports": 2, // 禁止重复导入
"no-new-symbol": 0, // 禁止 Symbol 操作符和 new 一起使用lines-between
"no-useless-computed-key": 2, // 禁止在对象中使用不必要的计算属性
"no-useless-constructor": 2, // 禁用不必要的构造函数
"no-useless-rename": 2, // 禁止在 import 和 export 和解构赋值时将引用重命名为相同的名字
"no-var": 2, // 要求使用 let 或 const 而不是 var
"object-shorthand": 2, // 要求对象字面量简写语法
"prefer-arrow-callback": 2, // 要求使用箭头函数作为回调
"prefer-const": 1, // ??? 建议使用const
"prefer-destructuring": [2, { // 优先使用数组和对象解构
"array": false,
"object": true
}],
"prefer-rest-params": 2, // 使用剩余参数代替 arguments
"prefer-spread": 2, // 建议使用扩展运算符而非.apply()
"prefer-template": 2, // 建议使用模板而非字符串连接
"require-yield": 2, // 禁用函数内没有yield的 generator 函数
"rest-spread-spacing": 2, // 强制剩余和扩展运算符及其表达式之间有空格
"template-curly-spacing": 2, // 强制模板字符串中空格的使用
"sort-imports": [0, { // ??? import 排序 问题是要以字母排序
ignoreCase: true,
ignoreMemberSort: true,
memberSyntaxSortOrder: ['all', 'single', 'multiple', 'none']
}], //
}
};
1.全局安装
npm install -g yalc
npm run build
yalc publish
yalc add @xin/xin-statistic
然后会发现
"yalc": "npm run build && yalc push"
import { echartsService } from '@xin/xin-statistic/src/statistic/echarts/index';
每次修改完只需要:yalc push 即可
yalc remove --all
npm install -g yarn
npm run yarn
echo "hi-enterprise-platform依赖安装完成"
cd packages/backend
npm run yarn
echo "backend依赖安装完成"
cd ../old-backend
npm run yarn
echo "old-backend依赖安装完成"
cd ../../../hi-enterprise-platform
node scripts/dev/setup.js
echo "一键初始化完成,请运行npm run start"
在pagejson中
"setup": "sh scripts/dev/setup.sh",
举个栗子
"devDependencies": {
"antd": "^3.1.4",
"babel-plugin-import": "~1.1.0",
"classnames": "2.2.5",
"qs": "^6.3.0",
"robe-ajax": "^1.0.1",
"expect": "^1.20.2",
"js-cookie": "^2.1.3",
.......
}
(1)指定版本:比如"classnames": "2.2.5",表示安装2.2.5的版本
(2)波浪号~+指定版本:比如 "babel-plugin-import": "~1.1.0",表示安装1.1.x的最新版本(不低于1.1.0),但是不安装1.2.x,也就是说安装时不改变大版本号和次要版本号
(3)^+指定版本:比如 "antd": "^3.1.4",,表示安装3.1.4及以上的版本,但是不安装4.0.0,也就是说安装时不改变大版本号。
1.创建文件夹
mkdir -p xxxxx
2.复制文件到某目录下
cp -rf packages/backend/dist/* output/ge //复制 packages/backend/dist下所有内容到 output/ge目录下
3.压缩文件
cd output
zip -r output.zip .
4.强制递归删除文件
rm -rf
5.递归复制
cp -rf
if (process.env.npm_config_report) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}
"analyz": "npm_config_report=true npm run build",
npm run analyz
当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。
域名对应错误 IP 地址,那么就会起到屏蔽的作用。比如:127.0.0.1 www.zuohaotu.com
spring cloud @FeignClient 多个服务间调用,可以用 IP + 域名 配置到hosts 文件里面,本地启动也可以无感调用其它服务。 比如,你配置的测试环境的 IP + 域名,那么你本地跑项目也可以调测服上面的服务。
查询 IP的地址:www.ipaddress.com/
npm install express # 本地安装
npm install express -g # 全局安装
https://yarnpkg.com/zh-Hans/docs/cli/
npm install -g nrm
npm ls 列出已安装的包
nrm use local
nrm del
nrm add
nrm test npm//测试源的速度
Webpack 会遍历你的应用程序中的所有文件,并启动一个开发服务器,然后将整个代码渲染到开发环境中。
webpack从一个entry.js文件开始,将其依赖的所有js或者其他assets通过loader打包成一个文件, 随后这个打包后的文件将被从server传递到客户端浏览器运行。
因为这样的处理规则,当保存文件时,整个 JavaScript 包将由 Webpack 重新构建,这就是为什么更改可能需要长达 10 秒才能反映在浏览器中,更新速度会随着应用体积增长而直线下降。
Vite 的工作方式不同,它不会遍历整个应用程序,Vite 只是转换当时正在使用的文件/模块。
Vite的核心理念:非捆绑开发构建
Vite 的核心**:浏览器请求它时,使用 ES 模块转换并提供一段应用程序代码。
开始开发构建时,Vite首先将JavaScript 模块分为两类:依赖模块和源码模块。
依赖项模块是第三方依赖的代码,从node_modules文件夹中导入的JavaScript 模块。这些模块将使用esbuild进行处理和捆绑,esbuild是一个用 Go 编写的 JavaScript 打包工具,执行速度比 Webpack 快 10-100 倍。
源码模块是源代码,即业务代码,通常涉及特定库的扩展,如:.jsx、.vue、.scss文件。
它使用基于路由的代码拆分来了解代码的哪些部分实际需要加载,因此,它不必重新打包所有内容。
它还使用现代浏览器中的原生 ES 模块支持来交付代码,这让浏览器可以在开发中承担打包工作。
在生产方面,虽然现在所有主流浏览器都支持原生 ES 模块,但它实现了诸如 tree-shaking、延迟加载和通用块拆分等性能优化技术,仍然比非打包应用程序带来更好的整体性能。出于这个原因,Vite附带了一个预先配置的build命令,该命令使用Rollup打包来打包和实现各种性能优化。
Webpack 这样的基于打包器的工作流必须在单个浏览器请求之前处理整个 JavaScript 模块,但 Vite 只在单个浏览器请求之前处理依赖模块。这就是为什么 Vite 能够比 Webpack 更快地处理开发构建。
Lerna的目录结构
multi-packages/
package.json
packages/
package-1/
package.json
package-2/
package.json
packages文件夹就是用来承载多个项目的目录
lerna项目中最常用到的命令是
lerna bootstrap
lerna publish。
npm i -g lerna
//或
yarn global add lerna
然后 lerna init --生成packages文件夹和lerna.json文件。并在package.json文件中的devDependencies字段中生成lerna对应的依赖信息。
固定模式是默认的模式,版本号使用 lerna.json 文件中的 version 属性。执行 lerna publish 时,如果代码有更新,会自动更新此版本号的值。
独立模式,允许维护人员独立的增加修改每个包的版本,每次发布,所有更改的包都会提示输入指定版本号。
使用方式:
lerna init --independent
修改 lerna.json 中的 version 值为 independent ,可将固定模式改为独立模式运行。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.