blog
blog copied to clipboard
自己搭建一个Vue项目工程
这里的意思是不在使用Vue-cli脚手架生成项目了,而是自己从零开始配置webpack打包,完成一个完整的项目。
首先说一下为什么不在使用脚手架,首先是脚手架一般不适合在公司作为项目开发的主力军,脚手架配置并不符合公司的业务场景,一般还要拓展一些额外的功能,在现有的脚手架中修改变得额外的麻烦,所以一般公司都是开发人员自己配置项目打包。
现在我们开始吧!
配置ES6
为了支持ES6,你需要安装如下包
babel-loader 在webpack中必须要loader才能处理代码,所以要安装loader
@babel/core 这个是babel里面自己的方法
@babel/preset-env 这里是将现有已经支持的高级语法转换成低级语法
@babel/runtime-corejs3 这个是浏览器还没有的语法,也就是提案中的语法,浏览器没有,就自己实现,这个包就是实现的所有提案代码
@babel/runtime 如果每个代码都使用了提案的代码,那么每个代码都有一个实现的方法,这样就重复了,那么就要使用把他们放到一个单独的文件中,作为模块带引入
@babel/plugin-transform-runtime 具体怎么引入,需要生成一段代码import这样的添加到我们的代码中,之前是没有的,要用来生成插入到我们的代码中
@babel/plugin-proposal-class-properties 这次插件是支持一些类里面的写法,可以选择性的安装
我们开始安装把,主要是开发依赖还是生成依赖
npm i @babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader @babel/plugin-proposal-class-properties -D
npm i @babel/runtime @babel/runtime-corejs3 -S
然后创建.babelrc
文件
{
"presets": ["@babel/preset-env"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3,
"helpers": true,
"regenerator": true,
"useESModules": false
}
],
"@babel/plugin-proposal-class-properties"
]
}
我们在开始创建我们的文件
build
webpack.base.conf.js
webpack.dev.conf.js
webpack.dll.conf.js
webpack.pro.conf.js
src
main.js
App.vue
template.html
我们的webpack配置都写在build文件夹中,现在在webpack.base.conf.js添加代码,这是公共的webpack代码配置
const path = require('path')
const webpack = require('webpack')
const dir = process.cwd()
module.exports = {
entry: {
app: path.resolve(dir, 'src/main.js')
},
resolve: {
extensions: [
'.js', '.vue', '.less', '.css' // 这个是配置node查找文件的顺序
],
alias: {
'src': path.resolve(dir, 'src') // 这个是配置路径别名的
}
},
module: {
rules: [
{
test: /\.js$/,
include: dir,
exclude: /node_modules/,
loader: 'babel-loader'
},
]
}
}
现在在webpack.dev.conf.js添加代码,这是开发环境的代码位置
const webpack = require('webpack')
const path = require('path')
const Merge = require('webpack-merge')
const dir = process.cwd()
const baseConfig = require('./webpack.base.conf')
module.exports = Merge(baseConfig, {
mode: 'development',
output: {
filename: '[name].js',
path: path.resolve(dir, 'dist')
},
devtool: 'source-map'
})
配置Vue
配置Vue我们需要安装 vue-template-compiler 模板编译的包,还有loader处理
npm i vue-loader vue-template-compiler -D
然后再在基础的webpack配置中添加规则,一定要记住添加把 VueLoaderPlugin 添加到插件中
const path = require('path')
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const dir = process.cwd()
module.exports = {
entry: {
app: path.resolve(dir, 'src/main.js')
},
resolve: {
extensions: [
'.js', '.vue', '.less', '.css'
],
alias: {
'src': path.resolve(dir, 'src')
}
},
module: {
rules: [
{
test: /\.jsx$/,
include: dir,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
new VueLoaderPlugin()
]
}
加载样式
样式的话我们使用less,我们需要安装三个loader
npm i less less-loader style-loader css-loader -D
webpack会调用less-loader处理less文件,而处理less文件需要less来编译成CSS css-loader 处理 @import 和 url() 转换成 import/require() 打包的时候才可以处理文件之间的依赖关系 style-loader 创建一个style把样式插入到HTML中。
修改我们的开发环境的webpack配置添加规则
{
test: /\.(css|less)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'less-loader',
options: {
sourceMap: true
}
}
]
}
加载图片
因为像 .png 这样的文件不是一个 JavaScript 模块,你需要配置 webpack 使用 file-loader 或者 url-loader 去合理地处理它们。
转换资源 URL 的好处是:
file-loader 可以指定要复制和放置资源文件的位置,以及如何使用版本哈希命名以获得更好的缓存。此外,这意味着 你可以就近管理图片文件,可以使用相对路径而不用担心部署时 URL 的问题。使用正确的配置,webpack 将会在打包输出中自动重写文件路径为正确的 URL。
url-loader 允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数。如果文件大于该阈值,会自动的交给 file-loader 处理。
安装依赖
npm i file-loader url-loader -D
在开发环境的webpack配置中添加对应的规则
{
test: /\.(png|svg|jpe?g)$/i,
loader: 'url-loader',
options: {
esModule: false
}
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
loader: 'file-loader',
options: {
esModule: false
}
},
动态连接库
我们通常需多次打包Vue全家桶,但是我们每次打包都费时费力,所以可以提前进行打包处理,那就要使用到动态连接库
// webpack.dill.js
const webpack = require('webpack')
const path = require('path')
const dir = process.cwd()
module.exports = {
mode: 'production',
entry: {
vendor: ['vue', 'vuex', 'vue-router']
},
output: {
library: 'familybucket',
filename: '[name].dll.js'
},
plugins: [
new webpack.DllPlugin({
name: 'familybucket',
path: path.resolve(dir, 'manifest.json')
})
]
}
打包完成之后会生成vendor.dll.js文件,这个文件需要在HTML模板中引用,还有manifest.json文件,这个文件需要在webpack中引用,我们需要修改基础的webpack配置
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const dir = process.cwd()
module.exports = {
entry: {
app: path.resolve(dir, 'src/main.js')
},
resolve: {
extensions: [
'.js', '.vue', '.less', '.css'
],
alias: {
'src': path.resolve(dir, 'src')
}
},
module: {
rules: [
{
test: /\.(jsx?|babel|es6)$/,
include: dir,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(dir, 'template.html'),
chunks: ['app']
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(dir, 'manifest.json')
}),
new AddAssetHtmlPlugin({ filepath: path.resolve(dir, 'dist/vendor.dll.js') }),
new ProgressBarPlugin(),
new VueLoaderPlugin()
]
}
我们需要安装依赖
npm i add-asset-html-webpack-plugin html-webpack-plugin progress-bar-webpack-plugin -D
我们通过add-asset-html-webpack-plugin这个插件可以在HTML模板中添加任何我们想要的静态资源 html-webpack-plugin是把HTML模板中添加我们打包后的JS文件 progress-bar-webpack-plugin 这个是打包使用使用的进度条方便我们查看
代码校验
我们需要使用的依赖有
npm i eslint-loader eslint eslint-friendly-formatter -D
在开发的webpack中添加对应的规则
{
enforce: 'pre',
test: /\.vue$/,
loader: 'eslint-loader',
exclude: /node_modules/,
include: path.resolve(dir, 'src'),
options: {
formatter: require('eslint-friendly-formatter'),
cache: true,
emitWarning: true,
emitError: true
}
},
关于eslint的使用是通过生成配置文件的,我们需要使用命令eslint --init
,通过问答的形式,最后生成了大概如下.eslintrc.js
module.exports = {
"env": {
"node": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:vue/essential"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"plugins": [
"vue"
],
"rules": {
"indent": ["error", 2],
"space-before-function-paren": ["error", "always"],
"quotes": ["error", 'single']
}
};
生成了这个文件,编辑器才有代码校验,会进行报错,通常我们如果报错,页面要直接显示出来,要配置webpack-dev-server插件中的配置选项
devServer: {
host: '0.0.0.0',
port: 8000,
hot: true,
open: true,
overlay: {
errors: true, // 页面显示报错信息
warnings: true // 页面显示报错信息
},
contentBase: path.resolve(dir, 'dist')
},
CSS前缀
需要安装
npm i postcss-loader postcss-preset-env cssnano mini-css-extract-plugin -D
这里说明一下,postcss-loader会调用postcss-preset-env来添加前缀,负责添加前缀的是postcss-preset-env,而 cssnano 这个包是负责删除无用的CSS,还有mini-css-extract-plugin是用来分离css成单独的文件的。下面是生成环境的配置。
const webpack = require('webpack')
const path = require('path')
const Merge = require('webpack-merge')
const dir = process.cwd()
const baseConfig = require('./webpack.base.conf')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = Merge(baseConfig, {
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin(),
new UglifyJsPlugin()
]
},
mode: 'production',
output: {
filename: 'js/[name]_[hash].js',
path: path.resolve(dir, 'dist')
},
module: {
rules: [
{
test: /\.(png|svg|jpe?g)$/,
loader: 'url-loader',
options: {
limit: 8192,
name: 'img/[name].[hash:7].[ext]',
publicPath: '/',
esModule: false
}
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:7].[ext]',
esModule: false
}
},
{
test: /\.(css|less)$/,
loaders: [
{
loader: MiniCssExtractPlugin.loader,
options: {
insertAt: 'top'
}
},
{
loader: 'css-loader',
options: { importLoaders: 2 }
},
'postcss-loader',
'less-loader'
]
}
]
},
devtool: 'cheap-source-map',
plugins: [
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify('production')
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*', '!vendor.dll.js']
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:7].css'
})
]
})
上面还有一下没有提到的插件,包括压缩css和压缩js的功能,需要安装
npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
记住新版本的webpack是写法不一样,要写到optimization.minimizer里面
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin(),
new UglifyJsPlugin()
]
},
清除之前
我们往往需要清除之前的打包文件,需要安装依赖是
npm i clean-webpack-plugin -D
用法是
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*', '!vendor.dll.js']
}),
在这里说明一下,配置cleanOnceBeforeBuildPatterns传个数组过来,!非号表示不要清除的,*星号表示所有的都要清除