前端开发node环境是必不可少的,如果你还没安装node环境,请先安装node,最新稳定版本。安装教程自行百度(PS: 一搜一大把)
两大必备利器:
npm install依赖包安装规则:
npm i xxx --save <===> npm i xxx -S 用于安装 项目(运行时,发布到生成环境时)所用到的依赖。会安装到 package.json文件的 dependencies下
npm i xxx --save-dev <===> npm i xxx -D 用于安装 项目构建(开发时,打包时)所用到的依赖。会安装到 package.json文件的 devDependencies下
npm run dev <===> npm dev (是在package.json文件的scripts下配置的执行命令)。
设置 NODE_DEV时需注意 window和mac有所不同:
window set NODE_ENV=production && xxxx
mac NODE_ENV=production 空格 xxxx
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
在根目录下创建build文件夹,在其下创建 webpack.base.js webpack.dev.js webpack.prod.js用于配置webpack
根目录下创建src目录,用于存放源代码
如果要上传至自己的github等远程仓库的话,别忘了配置 .gitignore文件
webpack常用的几个配置项:
entry:入口,可为字符串和对象,分别代码单入口和多入口。
output: 出口,配置打包文件输出的路径和名称等。
mode:环境,可选值有 development production none。
module: 模块,其选项决定了如何处理项目中的不同类型的模块。其中rules选项用于配置各种各样的loader。
resolve:解析,配置模块如何解析;其中选项alias用来创建 import
或 require
的别名,来确保模块引入变得更简单。extensions选项用于配置按照一定顺序解析文件后缀名。
plugins:插件,用于增强webpack的构建能力,通常是处理一些loader无法完成的工作。
optimization:优化,会根据mode的值来执行不同的优化,当然你也可以自己手动配置和重写。
devServer:开发服务器,用于配置快速的开发应用程序。
devtool:用于控制是否生成,以及如何生成 source map。
const path = require('path')
const glob = require('glob');
// 自动生成html
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 配置通用的多页面应用入口,以及自动生成相应的html页面
// process.cwd()方法会返回 Node.js 进程的当前工作目录
const projectRoot = process.cwd()
const configEntry = () => {
const entry = {}
const htmlWebpackPlugins = []
const entryFiles = glob.sync(path.join(projectRoot, 'src/*/index.js'))
Object.keys(entryFiles).forEach((index) => {
// 配置入口
const entryFile = entryFiles[index]
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
// 配置对应的自动生成html
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
// 使用自定义模版, 需要在对应的目录下先创建自定义的template.html文件,否则会打包报错
template: path.join(projectRoot, `src/${pageName}/template.html`),
// 会将默认我们自定义的模版插入打包的css和js,重命名为index.html 并将其放到对应的出口目录下
filename: `${pageName}/index.html`,
chunks: [pageName],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
})
)
})
return {
entry,
htmlWebpackPlugins
}
}
const {entry, htmlWebpackPlugins} = configEntry()
output: {
// 输出文件的路径
path: path.join(projectRoot, 'dist'),
// 输出的文件名
filename: '[name]_[chunkhash:8].js'
},
npm i postcss-loader postcss postcss-preset-env -D 执行此命令添加 自动配置浏览器前缀的依赖。
npm i mini-css-extract-plugin -D 执行此命令,安装依赖 用来抽取css文件。
配置代码如下:
// 抽取css文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [{
test: /.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
["postcss-preset-env"]
]
},
}
},
'less-loader',
]
}]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css',
}),
],
}
{
test: /\.(png|jpg|jpeg|gif)$/i,
use: [{
loader: 'url-loader',
options: {
limit: false,
name: '[name]_[contenthash:8].[ext]',
outputPath: './assets/img'
}
}]
}
{
test: /\.(woff|woff2|eot|otf)$/,
use: [{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]',
outputPath: './assets/fonts'
}
}]
}
optimization: {
// 提取公共模块 包括第三方库和自定义工具库
splitChunks: {
minSize: 0,
chunks: "all", // async表示抽取异步模块,all表示对所有模块生效,initial表示对同步模块生效
cacheGroups: {
// styles: {
// name: 'prod',
// test: /\.(css|less|scss)/,
// chunks: 'all',
// enforce: true,
// // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
// reuseExistingChunk: true
// },
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
reuseExistingChunk: true
},
vendors: { // 抽离第三方库
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
utilCommon: { // 抽离自定义工具库
name: "common",
minSize: 0, // 将引用模块分离成新代码文件的最小体积
minChunks: 2, // 表示将引用模块如不同文件引用了多少次,才能分离生成新chunk
priority: -20
}
}
},
runtimeChunk: true,
minimize: true,
minimizer: [
new TerserPlugin({
// 开启/禁用多进程并发运行功能 并发运行的默认数量:os.cpus().length - 1,
// 可以直接跟数字,进行并发运行数量的设置
parallel: true,
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
pure_funcs: ['console.log', 'debugger'] // 移除console
},
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
}
}
}),
]
},
1. 在根目录下创建.eslintrc.js文件,在文件内可配置如下:
module.exports = {
"parser": "babel-eslint",
"extends": "airbnb-base",
"env": {
"browser": true,
"node": true
}
}
2.安装eslint相关依赖,npm run i eslint babel-eslint eslint-config-airbnb-base -D
git提交规范检测要借助 husky实现,安装依赖 npm i husky @commitlint/config-conventional @commitlint/cli -D
在 package.json文件中添加如下代码:
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
软件版本通常由三位组成,形如:X.Y.Z
我们在通常发布版本时为了避免出现循环依赖,减少依赖冲突,需遵循git官方提倡的semver规范。
语义化版本规范格式:
主版本号:当你做了不兼容的API的修改;
次版本号:当你做了向下兼容的功能性的增强;
修订号:当你做了向下兼容的bug修复;
1. 可以使用webpack内置的stats进行分析,stats构建的统计信息。在package.json文件中使用stats
"scripts": {
"build:stats": "webpack --config build/webpack.prod.js --json > stats.json",
},
// 此命令执行完毕后会在根目录输出stats.json文件,文件内包含了打包的统计信息
2. 在nodejs中使用
const webpack = require('webpack')
const config = require('./build/webpack.prod.js')('production')
webpack(config, (err, stats) => {
if(err){
return console.error(err)
}
if(stats.hasErrors){
return console.error(stats.toString('errors-only'))
}
console.log(stats)
})
上述两种方法 颗粒度太粗,看不出问题所在。
打包体积分析
借助于webpack-bundle-analyzer插件来分析打包的体积,从而发现大的打包文件,进行针对性的优化。
执行 npm install webpack-bundle-analyzer --save-dev,代码如下:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
// 开启 BundleAnalyzerPlugin
new BundleAnalyzerPlugin()
]
提升构建速度(多进程打包)
使用 thread-loader,首先执行npm i thread-loader -D 使用方式参考webpack官网, 移步这里
预编译资源模块(使用dllPlugin)
使用缓存,开启babel-loader的缓存,使用TerserPlugin(webpack5.0自带了该插件,已经进行了一些优化的默认配置),使用cache-loader进行模块的缓存。
缩小构建目标范围:1.优化resolve.moduled配置来减少模块搜索层级。2. 优化resolve.mainFields配置。 3. 优化resolve.extensions配置。4.合理使用alias
图片压缩处理:imagemin. 使用image-webpack-loader
构建体积优化:使用动态Polyfill。 polifill-service其原理是识别User Agent 下发不同的Polyfill https://polyfill.io/v3/