基础常识:
查看版本号:
vue -V
webpack -v 查看当前版本
已有项目升级webpack到最新版:
删除node_modules目录
进入package.json文件修改版本号到最新
npm install --save-dev webpack
升级webpack到最新版:
删除node_modules目录
npm install --save-dev webpack
npm -v/cnpm -v
简介:此项目为vue2.x 使用webpack4构建项目的文档教程,自我学习保存。
前言:为了方便项目的存储,可以先在码云上建个仓库,git clone一下,然后修改下.gitignore文件 将node_modules/ 和 /dist/ 加入,最好从其他项目中复制一份过来。
好了,正文开始:
1.npm init 生成 packge.json文件
2.安装必要依赖
(1)npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev
webpack-cli: webpack中分离出来的
webpack-dev-server
webpack-merge
(2)npm i vue vue-router vuex --save
3.创建目录结构
|--dist
|--build
|--webpack.prod.js
|--webpack.dev.js
|--webpack.base.js
|--src
|--index.js
|--app.vue
|--router.js
|--store.js
|--assets
|--components
|--views
|--index.html
4.安装vue核心解析插件 npm i vue-loader vue-template-compiler --save-dev
5.安装其他的loader
在同一个 test 下配置多个loader时,优先处理的 loader 放在配置数组的后面
(1)必要的:
CSS 基础 loader:
css-loader: "^1.0.0", // 加载.css文件
style-loader: "^0.21.0", //使用<style>将css-loader内部样式注入到我们的HTML页面
file-loader// 解析图片,字体等
url-loader //设置上limit选项,将小于limit的图片转编码,大于limit的交给file-loader复制路径来引用使用
注意:具体参考vue-webpack模板,配置url-loader后不需要配置file-loader,但可在url-loader中添加name字段,file-loader会实现name字段内容。文末会放上build文件夹下,三个配置文件的代码。
npm i babel-core --save-dev
npm i @babel/core --save-dev
@babel/preset-env --save-dev // 是一个配置文件,我们可以使用这个配置文件转换 ES2015/ES2016/ES2017 到 ES5
babel-preset-env 这个是旧版本的
.babelrc文件:
{
"presets": ["@babel/preset-env"]
}
npm i babel-loader --save-dev //可以把ES6语法转为ES5语法
npm i html-webpack-plugin --save-dev //安装 html 模板解析插件
npm i clean-webpack-plugin --save-dev //解决每次重新打包,dist 文件夹文件未清除
(2)选择性的:
CSS 前处理 less 两件套
"less": "^3.8.0",
"less-loader": "^4.1.0",
CSS 前处理 sass 两件套
"node-sass": "^4.9.2",
"sass-loader": "^7.1.0",
CSS 后处理 postcss 两件套
"postcss-loader": "^2.1.6",
"autoprefixer": "^9.1.0",
npm install mini-css-extract-plugin --save-dev //webpack4中分离CSS。插件来分离 css。
注意:这个插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR,具体看模板文件配置
npm install image-webpack-loader --save-dev //图片压缩
npm i optimize-css-assets-webpack-plugin --save-dev // css代码压缩,优化css结构,利于网页加载和渲染
npm i uglifyjs-webpack-plugin --save-dev // js代码压缩
npm i --save-dev cross-env 能跨平台地设置及使用环境变量,不同平台使用唯一指令,无需担心跨平台问题。
总结一下loader的常用四种写法:
use: [xxx, xxx]
use: [{loader: XXX}, {loader: XXX}]
use: [{
loader: XXX,
options: {}
}, 'XXX']
loader: [XXX, XXX]
loader的options配置项里面还可以放置loader,also plugins
常用的loader:
- 处理样式的:style-loader,css-loader,postcss-loader,sass-loader,less-loder
- 处理es6的:babel-loader(要连同babel-core, babel-preset-env)一起用
- 处理图片的:file-loader, url-loader, image-webpack-loader
常用的plugin:
- 压缩js:uglifyjs-webpack-plugin
- 合并&压缩css: mini-css-extract-plugin,optimize-css-assets-webpack-plugin
- 清除目录:clean-webpack-plugin
- 生成html:html-webpack-plugin
- postcss相关的:postcss-plugin-px2rem,postcss-preset-env,postcss-sprites,autoprefixer
- webpack自带的方法:webpack.ProvidePlugin等
build文件夹下的配置文件:
webpack.base.js
// webpack.base.js
// 存放 dev 和 prod 通用配置
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
//mini-css-extract-plugin插件应该只用在 production 配置中,并且在loaders链中不使用 style-loader, 特别是在开发中使用HMR,因为这个插件暂时不支持HMR
const devMode = process.env.NODE_ENV !== 'production';
//console.log(process.env.NODE_ENV,"devMode--------------")
//webpack4 分离css插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
//使用 WEBPACK_SERVE 环境变量检测当前是否是在 webpack-server 启动的开发环境中
//const dev = Boolean(process.env.WEBPACK_SERVE)
// 使用happypack---加速webpack打包
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({
size: os.cpus().length
});
module.exports = {
entry: './src/index.js', //入口
/*
配置各种类型文件的加载器,称之为 loader
webpack 当遇到 import ... 时,会调用这里配置的 loader 对引用的文件进行编译
*/
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
// 正则匹配所有以.css结尾的文件
// 它会应用到普通的 `.css` 文件
// 以及 `.vue` 文件中的 `<style>` 块
test: /\.(sa|sc|c)ss$/,
// 使用css-loader和style-loader依次对css文件进行处理
/*
先使用 css-loader 处理,返回的结果交给 style-loader 处理。
css-loader 将 css 内容存为 js 字符串,并且会把 background,
@font-face 等引用的图片,字体文件交给指定的 loader 打包,
*/
// 按照数组中从后往前的顺序
use: [
devMode?'vue-style-loader':{
loader:MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
/***
**还没有尝试css-loader的url属性是否可行
***/
/* {
loader: 'css-loader',
options: {
url: false, // css中加载图片的路径将不会被解析 不会改变
minimize: true, //
importLoaders: 1
}
}, */
'css-loader',
'sass-loader'
]
},
// 图片处理
{
//test: /\.(gif|png|jpe?g|svg)$/i,
test: /\.(png|jpg|jpeg|gif|svg|svgz)(\?.+)?$/,
//enforce: 'pre', // 这会应用该 loader,在其它之前
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //单位Bytes,即转换8KB以下的图
// 当图片大于8192时,分离图片至imgs文件夹
// [ext]是占位符 表示文件的后缀名
/* name: devMode ? "img/[name].[ext]" : "img/[hash:6][name].[ext]" */
name: devMode ? "[name].[ext]" : "[hash:6][name].[ext]",//和注释那行的效果一样
publicPath: "./img/",
outputPath: "img/"
/* fallback: ['file-loader','image-webpack-loader'],
quality: 85 */
}
},
// 图片压缩
//'file-loader',
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 8192,
name: devMode ? "fonts/[name].[ext]" : "fonts/[hash:3][name].[ext]"
}
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/
/* exclude: __dirname + 'node_modules',
include: __dirname + 'src',
options: {
presets: ['env']
} */
},
{
test: /\.js$/,
//把对.js 的文件处理交给id为happyBabel 的HappyPack 的实例执行
loader: 'happypack/loader?id=happyBabel',
//排除node_modules 目录下的文件
exclude: /node_modules/
}
]
},
/*
配置 webpack 插件
plugin 和 loader 的区别是,loader 是在 import 时根据不同的文件名,匹配不同的 loader 对这个文件做处理,
而 plugin, 关注的不是文件的格式,而是在编译的各个阶段,会触发不同的事件,让你可以干预每个编译阶段。
*/
plugins: [
/*
html-webpack-plugin 用来打包入口 html 文件
entry 配置的入口是 js 文件,webpack 以 js 文件为入口,遇到 import, 用配置的 loader 加载引入文件
但作为浏览器打开的入口 html, 是引用入口 js 的文件,它在整个编译过程的外面,
所以,我们需要 html-webpack-plugin 来打包作为入口的 html 文件
*/
new HtmlWebpackPlugin({
/*
template 参数指定入口 html 文件路径,插件会把这个文件交给 webpack 去编译,
webpack 按照正常流程,找到 loaders 中 test 条件匹配的 loader 来编译,那么这里 html-loader 就是匹配的 loader
html-loader 编译后产生的字符串,会由 html-webpack-plugin 储存为 html 文件到输出目录,默认文件名为 index.html
可以通过 filename 参数指定输出的文件名
html-webpack-plugin 也可以不指定 template 参数,它会使用默认的 html 模板。
*/
template: path.resolve(__dirname, '../index.html'),
}),
new VueLoaderPlugin(),
//
new MiniCssExtractPlugin({
filename: devMode ? 'css/[name].css' : 'css/[name].[hash:5].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash:5].css',
}),
// 解决vender后面的hash每次都改变
/*
使用文件路径的 hash 作为 moduleId。
虽然我们使用 [chunkhash] 作为 chunk 的输出名,但仍然不够。
因为 chunk 内部的每个 module 都有一个 id,webpack 默认使用递增的数字作为 moduleId。
如果引入了一个新文件或删掉一个文件,可能会导致其他文件的 moduleId 也发生改变,
那么受影响的 module 所在的 chunk 的 [chunkhash] 就会发生改变,导致缓存失效。
因此使用文件路径的 hash 作为 moduleId 来避免这个问题。
*/
new webpack.HashedModuleIdsPlugin(),
//happyPack实例
new HappyPack({
//用id来标识 happypack处理那里类文件
id: 'happyBabel',
//如何处理 用法和loader 的配置一样
loaders: [{
loader: 'babel-loader?cacheDirectory=true',
}],
//共享进程池
threadPool: happyThreadPool,
//允许 HappyPack 输出日志
verbose: true,
//启用debug 用于故障排查。
debug: false
}),
//设置环境变量信息
new webpack.DefinePlugin({
//鸡肋功能?
/* 'process.env':{
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
} */
})
] // 插件
};
webpack.dev.js
// webpack.dev.js
// 存放 dev 配置
const merge = require('webpack-merge');
const common = require('./webpack.base.js');
const path = require('path');
module.exports = merge(common, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: { // 开发服务器
// dev-server 服务路径
contentBase: path.join(__dirname, "dist"),
compress: true,
host: '0.0.0.0',
//host: 'localhost',
port: 8085,
// 自动打开浏览器
open: true,
// 启动热更新
hot: true,
// 显示 webpack 构建进度
progress: true,
//重载脚本出现在包中,构建消息会出现在控制台。
inline: true,
// 在页面上全屏输出报错信息
overlay: {
warnings: true,
errors: true
},
clientLogLevel: 'warning',
// 可以进行接口代理配置
proxy: {
"/api": {
target: "http://erp.my012.com:8081",
//https会用到
secure: false
}
},
publicPath: '/'
},
output: { // 输出
filename: 'js/[name].[hash].js', // 每次保存 hash 都变化
path: path.resolve(__dirname, '../dist')
},
module: {},
plugins: [
//命令行模式 --hot 将会自动添加此插件
//new webpack.HotModuleReplacementPlugin()
]
});
webpack.prod.js
// webpack.prod.js
// 存放 prod 配置
const path = require('path');
// 合并配置文件
const merge = require('webpack-merge');
const common = require('./webpack.base.js');
// 打包之前清除文件
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 分离CSS插件
//const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 压缩CSS和JS代码
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
//const process.env.NODE_ENV = 'production'
module.exports = merge(common, {
module: {},
/*
webpack 执行模式
development:开发环境,它会在配置文件中插入调试相关的选项,比如 moduleId 使用文件路径方便调试
production:生产环境,webpack 会将代码做压缩等优化
*/
mode: 'production',
devtool: 'cheap-module-source-map',
output: {
filename: 'js/[name].[contenthash].js', //contenthash 若文件内容无变化,则contenthash 名称不变
// 打包输出目录
path: path.resolve(__dirname, '../dist')
},
plugins: [
new CleanWebpackPlugin(['dist/*'], {
root: path.resolve(__dirname, '../')
})
/* new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
chunkFilename: 'css/[id].[hash].css'
}) */
],
//分离不常变化的文件, 如 node_modules 下引用的库---webpack中的字段
optimization: {
// 分离chunks
splitChunks: {
/*
默认 entry 的 chunk 不会被拆分
因为我们使用了 html-webpack-plugin 来动态插入 <script> 标签,entry 被拆成多个 chunk 也能自动被插入到 html 中,
所以我们可以配置成 all, 把 entry chunk 也拆分了
*/
chunks: 'all',
cacheGroups: {
common:{
/* chunks: "initial",
minChunks: 2,
maxInitialRequests: 5,
minSize: 10000 */
},
vendor: {
test: /[\\/]node_modules[\\/]/,
chunks: "initial", // 只打包初始时依赖的第三方
name: "vendor",
priority: 10
//enforce: true //
},
styles: {
/* name: 'style',
test: /\.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true */
}
}
},
/* runtimeChunk: {
name: "manifest"
}, */
minimizer: [
// 压缩JS-- 自定义js优化配置,将会覆盖默认配置
new UglifyJsPlugin({
exclude: /\.min\.js$/, // 过滤掉以".min.js"结尾的文件,我们认为这个后缀本身就是已经压缩好的代码,没必要进行二次压缩
uglifyOptions: {
compress: {
warnings: true, // 去除警告
drop_debugger: true, // 去除debugger
drop_console: true // 去除console.log
}
},
cache: true, // 开启缓存
parallel: true, // 平行压缩,开启并行压缩,充分利用cpu
sourceMap: false, // set to true if you want JS source maps
extractComments: true // 移除注释
}),
// 压缩css
new OptimizeCSSAssetsPlugin({})
]
}
});