项目骨架
代码语言:javascript复制 object
--dist
--src
----assets
------images
------styles
----index.js
----app.vue
--webpack.config.js
dist目录存放编译后的资源 src存放源码文件 运行命令 npm init -y
one
首先安装基础包 npm i webpack webpack-cli
npm i vue vue-loader vue-template-compiler css-loader style-loader
在/src/app.vue键入如下测试代码
代码语言:javascript复制<template>
<h1>
{{title}}
</h1>
</template>
<script>
export default {
data(){
return {
title:'Hello Vue!'
}
}
}
</script>
<style>
</style>
在/src/index.js键入如下代码
代码语言:javascript复制import Vue from 'vue'
import app from './app'
const root = document.createElement('div')
document.body.appendChild(root)
new Vue({
render:(h)=>h(app)
}).$mount(root)
上面代码的创建了一个vue实例,并将其挂载到html节点
由于使用了.vue
文件我们要配置webpack,并且设置resolve修改vue的默认引入
webpack 默认引入vue版本是一个运行时版本,开发阶段我们将其修改为完整的版本
在/webpack.config.js键入如下
代码语言:javascript复制const path = require('path')
module.exports = {
mode:"development",
entry:{
path:path.join(__dirname,"./src/index.js"),
},
output:{
path:path.join(__dirname,"dist"),
filename:"bundle.js"
},
module:{
rules:[
{test:/.vue$/,loader:"vue-loader"}
]
},
resolve:{
extensions:[".vue",".js",".jsx",".json"],
alias:{
"vue":"vue/dist/vue.esm.js"
}
}
}
接下来在package.json
设置编译资源的命令
...
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": " webpack --config webpack.config.js"
},
...
运行命令 npm run dev
报错如下
ERROR in ./src/app.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
我们要配置一个VueLoaderPlugin的插件才可以
代码语言:javascript复制//webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
...
plugins:[
new VueLoaderPlugin()
]
}
再次运行命令 npm run dev
即可
这个时候项目dist目录会生成bundle.js文件代码资源编译成功,博主这里暂不测试
two
上面我们已经可以将vue文件编译出来,这个时候可以考虑一些静态资源文件,比如css,图片资源等。
由于之前我们已经引入了css-loader ,style-loader
先以css文件为例, css 补充webpack.config.js
rules:[
{test:/.vue$/,loader:'vue-loader'},
{test:/.css$/,use:['style-loader','css-loader']}
]
在/src/index.js中引入/src/assets/styles/index.js文件
代码语言:javascript复制...
import './assets/styles/index.css'
...
运行命令 npm run dev
可以在bundle.js看到如下代码,这就是index.css的内容
body{\r\n background-color: red;\r\n}", ""])
图片资源
接下来我们可以试着打包项目中用到的图片 在 /src/assets/styles/index.js键入如下代码
代码语言:javascript复制body{
background-image: url('../images/bg.jpeg');
}
下载图片处理相关的包
代码语言:javascript复制npm i url-loader file-loader
补充webpack.config.js
代码语言:javascript复制 rules:[
{test:/.vue$/,loader:'vue-loader'},
{test:/.css$/,use:['style-loader','css-loader']},
{
test:/.(jpg|jpeg|png|gif|svg)$/,
use:[
{
loader:'url-loader',
options:{
//小于1M的转换为base64
limit:1024,
name:'[name].[ext]'
}
}
]
}
]
这里的loader使用了另一种配置方法,我们给url-loader设置了一些选项,具体参照 运行命令 npm run dev
在/dist/生成了bg.jpeg文件
此时可以使用普通的html文件引入bundle.js看看是否改变了body的背景。
css预处理
在项目中我们一般会用到css预处理器,那么这些与处理器如何通过webpack编译成普通的css文件 这里有stylus为例 安装stylus相关的包 npm i stylus stylus-loader
补充webpack.config.js
...
{test:/.styl/,use:['style-loader','css-loader','stylus-loader']},
...
运行 npm run dev 可以在bundle.js中看到stylus语法最终被编译成了css
代码语言:javascript复制h1[data-v-5ef48958] {\n color: #333;\n}\nh1 span[data-v-5ef48958] {\n font-size: 28px;\n}
three
区分环境
到目前为止我们的项目还没有跑起来过,这里我们可以使用devServer让我们的项目运行起来 由于devServer是运行在开发环境,所以我们区分环境的方式去配置webpack.config.js 引入 cross-env 用于区分当前环境 npm i cross-env
修改package.json
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"build":"cross-env NODE_ENV=production webpack",
"dev":"cross-env NODE_ENV=development webpack"
},
接下来我们就可以使用process.env获取到当前环境 在webpack.config.js
代码语言:javascript复制const path = require('path')
const isDev = process.env.NODE_ENV === 'development'
...
当然只区分环境是不够的,我们一般有三套配置,分别为基础配置、开发配置、生产配置然后根据环境变量运行不同的配置文件
引入模块合并配置文件 npm i webpack-merge -D
1.将webpack.config.js更名为webpack.base.js 2.新建webpack.dev.js用于设置开发环境配置 3.新建webpack.pro.js用于设置线上环境配置
webpack.base.js的内容
代码语言:javascript复制const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')
const HTMLPlugin = require('html-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'
module.exports = {
entry:{
path:path.join(__dirname,"./src/index.js"),
},
output:{
path:path.join(__dirname,"dist"),
filename:"bundle.js",
publicPath:'./'
},
module:{
rules:[
{test:/.vue$/,loader:'vue-loader'},
{test:/.css$/,use:['style-loader','css-loader']},
{test:/.styl/,use:['style-loader','css-loader','stylus-loader']},
{
test:/.(jpg|jpeg|png|gif|svg)$/,
use:[
{
loader:'url-loader',
options:{
//小于1M的转换为base64
limit:1024,
name:'[name].[ext]'
}
}
]
}
]
},
resolve:{
extensions:[".vue",".js",".jsx",".json"]
},
plugins:[
new VueLoaderPlugin(),
new webpack.DefinePlugin({
'process.env':{
NODE_ENV:isDev ? '"development"' : '"production"'
}
}),
new VueLoaderPlugin(),
new HTMLPlugin()
]
}
在webpack.base.js中我们进行了如下操作
1.我们移除了mode
和resolve.alias
配置项,因为这个两个配置项要区分环境去配置
2.设置了webpackDefinePlugin使当前环境能够在普通的js中得到应用 比如index.js使用console.log(process.env.NODE_ENV)
3.引入了HTMLPlugin,这个插件用于帮我们生成html 4.配置了output.publicPath
设置资源的根路径
在webpack.dev.js键入如下代码
代码语言:javascript复制const merge = require('webpack-merge');
const base = require('./webpack.base.js');
const webpack = require('webpack')
module.exports = merge(base,{
mode:'development',
devServer:{
port:520,
host:'127.0.0.1',
overlay:{
errors:true //有错误时显示在网页上
},
hot:true//配置热更新
},
resolve:{
alias:{
"vue":"vue/dist/vue.esm.js"
}
},
plugins:[
//热更新
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
]
})
在webpack.pro.js键入如下代码
代码语言:javascript复制let merge = require('webpack-merge');
let base = require('./webpack.base.js');
module.exports = merge(base,{
mode:'production',
resolve:{
alias:{
"vue":"vue/dist/vue.runtime.esm.js"
}
}
})
安装 npm i webpack-dev-server
高版本的cli 安装 @webpack/cli-serve
npm i html-webpack-plugin
修改package.json
代码语言:javascript复制 "scripts": {
"test": "echo "Error: no test specified" && exit 1",
"build": "cross-env NODE_ENV=production webpack --config webpack.pro.js",
"dev": "cross-env NODE_ENV=development webpack serve --config webpack.dev.js"
},
运行开发环境的命令 npm run dev
访问 localhost:520
可以看到项目运行成功
接下来我们在测试生产环境的命令 npm run build
生成如下文件
jsx
在vue中我们也可以使用jsx语法,用jsx写出来的组件比较灵活
代码语言:javascript复制npm i babel-plugin-transform-vue-jsx babel-plugin-syntax-jsx
安装预设 npm i @babel/core babel-loader @vue/babel-preset-app
配置.babelrc
{
"presets": [
"@vue/babel-preset-app"
]
}
补充webpack.base.js
代码语言:javascript复制{test:/.jsx/,loader:'babel-loader'},
写一个jsx测试组件
代码语言:javascript复制//footer.jsx
export default {
data(){
},
render(){
return (
<footer>copy right tzh</footer>
)
}
}
css自动加浏览器前缀
npm i postcss-loader autoprefixer
项目新建配置文件 postcss.config.js
并键入如下代码
const autoprefixer = require('autoprefixer')
module.exports = {
plugins:[
autoprefixer()
]
}
接下来修改相应配置,在css-loader处理前先交给postcss-loader处理
代码语言:javascript复制{
test:/.styl$/,
use:[
'style-loader',
'css-loader',
{
loader:'postcss-loader',
options:{
sourceMap:true
}
},//添加postcss处理
/**因为stylus-loader会自动生成sourceMap所以postcss-loader直接使用前面生成的即可 */
'stylus-loader'
]
}
到此我们可以说一个基本的Vue工程搭建完毕,当然其他的一些配置根据业务扩展即可比如es5 语法 由于每个项目的业务需求都不一样,这里只搭建基础工程 但是我们还可以对项目进行一些优化
优化
单独分离css
上面的配置是将css写到bundle.js里面的,一个线上的项目肯定不能这样做,我们要将其单独抽离处理充分利用浏览器的缓存机制! npm i mini-css-extract-plugin
文档
我们将webpack.base.js里面配置的styl(css同理)删除,区分环境处理
代码语言:javascript复制 rules:[
{test:/.vue$/,loader:'vue-loader'},
/*{test:/.css$/,use:['style-loader','css-loader']},*/
/* {test:/.styl/,use:['style-loader','css-loader','stylus-loader']},*/
{test:/.jsx/,loader:'babel-loader'},
在webpack.dev.js
devServer:{
port:520,
host:'127.0.0.1',
overlay:{
errors:true //有错误时显示在网页上
},
hot:true//配置热更新
},
module:{
rules:[
{
test:/.styl$/,
use:[
'style-loader',
'css-loader',
{
loader:'postcss-loader',
options:{
sourceMap:true
}
},//添加postcss处理
/**因为stylus-loader会自动生成sourceMap所以postcss-loader直接使用前面生成的即可 */
'stylus-loader'
]
}
]
},
...
在webpack.pro.js
代码语言:javascript复制let merge = require('webpack-merge');
let base = require('./webpack.base.js');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(base,{
mode:'production',
resolve:{
alias:{
"vue":"vue/dist/vue.runtime.esm.js"
}
},
module:{
rules:[
{
test:/.styl$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
{
loader:'postcss-loader',
options:{
sourceMap:true
}
},//添加postcss处理
'stylus-loader'
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'main.css'//生成的样式文件名称
})
]
})
npm run build
cssb被单独打包
单独打包类库文件
因为类库代码的稳定性较高,不需要经常迭代 我们需要浏览器尽可能长时间去缓存我们的静态文件 如果将类库文件和js文件打包到一起,那么类库文件将随着我们js 文件更新而更新,这样就不能最大限度的利用浏览器缓存
这个时候我们就不能以将所有文件都取名为bundle.js
在webpack.pro.js添加
代码语言:javascript复制...
output:{
filename:"[name].[chunkhash:8].js"
},
...
完整的webpack.pro.js
代码语言:javascript复制let merge = require('webpack-merge');
let base = require('./webpack.base.js');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(base,{
mode:'production',
resolve:{
alias:{
"vue":"vue/dist/vue.esm.js"
}
},
output:{
filename:"[name].[chunkhash:8].js"
},
module:{
rules:[
{
test:/.styl$/,
use:[
MiniCssExtractPlugin.loader,
'css-loader',
{
loader:'postcss-loader',
options:{
sourceMap:true
}
},//添加postcss处理
'stylus-loader'
]
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'main.css'//生成的样式文件名称
})
],
optimization:{
splitChunks:{
//分隔代码块
cacheGroups:{
//缓存组
vendor:{
//引用多次第三方模块
priority:1,//先抽离第三方模块
test:/node_modules/,
chunks:'initial',//入口处开始
minSize:0,//>0字节
minChunks:1,//用过1次以上
}
}
}
}
})
hash与chunkhash的区别
chunk:可以理解为在entry里面声明的不同节点 hash:所有打包的js模块都是同一个hash
所以类库打包时使用chunkhash,如果使用hash那么普通js文件改变后 类库文件也随着改变,这样就没有充分利用浏览器缓存