使用 webpack & Eslint 创建 vue 项目
源码部分详见:https://github.com/CrystalAngelLee/vue-webpack-demo
项目准备
mkdir webpack-vue-demo // 创建一个新的文件夹
cd webpack-vue-demo
yarn init --yes // 初始化 package.json
yarn add webpack webpack-cli --dev // 引入webpack
touch webpack.config.js // 创建webpack 配置文件
code . // 打开当前目录
项目基本配置
安装必要依赖
- vue:
yarn add vue
- vue 插件:
yarn add vue-loader vue-template-compiler --dev
- css 插件:
yarn add css-loader style-loader vue-style-loader less-loader --dev
- image插件:
yarn add file-loader url-loader --dev
- babel插件:
yarn add @babel/core @babel/cli @babel/preset-env babel-loader --dev
yarn add @babel/polyfill
- html 生成插件:
yarn add html-webpack-plugin --dev
- webpack 本地服务插件:
yarn add webpack-dev-server --dev
1. webpack基本配置
webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
}
package.json
{
"name": "webpack-vue-demo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^5.24.2",
"webpack-cli": "^4.5.0"
}
}
2. 资源文件处理
测试文件添加
- 添加html 文件
public\index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
- 添加图标
public\favicon.ico
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html", // 模板地址
filename: "index.html",
title: "vue demo", // title
favicon: "public/favicon.ico", // 图标
}),
],
}
3. 热部署
webpack.config.js
module.exports = {
devServer: {
contentBase: path.resolve(__dirname, "dist"), // html所在路径
compress: true, // 是否压缩
port: 3000, // 端口
hot: true, // 热部署
open: true, // 打包完成后自动打开网页
},
}
package.json
"scripts": {
"build": "webpack",
"serve": "webpack serve --config webpack.config.js"
},
4. vue 配置
webpack.config.js
const { VueLoaderPlugin } = require("vue-loader");
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /.css$/,
use: ["vue-style-loader", "style-loader", "css-loader"],
},
]
},
plugins: [
new VueLoaderPlugin(),
],
}
测试文件添加
-
src/App.vue
<template> <div class="example"> {{ msg }} </div> </template> <script> export default { data() { return { msg: 'Hello Webpack', }; }, }; </script> <style> .example { color: red; } </style>
-
src/main.js
import Vue from 'vue'; import App from './App.vue'; new Vue({ el: '#app', render: (h) => h(App), });
5.图片资源加载
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.(png|jpe?j|gif|svg)(\?.*)?$/,
use: {
loader: "url-loader",
options: {
limit: 10 * 1024, // 10 KB
},
},
},
]
}
}
测试文件添加
-
src\assets\logo.png
-
src\App.vue
<template> <div class="example"> {{ msg }} <img :src="url" /> </div> </template> <script> import logo from './assets/logo.png'; export default { data() { return { msg: 'Hello Vue1', url: logo, }; }, }; </script> <style> .example { color: red; } </style>
6. babel
webpack.config.js
module.exports = {
entry: ["@babel/polyfill", "./src/main.js"],
module: {
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
},
}
}
touch .babelrc
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry"
}
]
]
}
测试文件添加 src\App.vue
<template>
<div class="example">
{{ msg }}
<img :src="url" />
</div>
</template>
<script>
import logo from './assets/logo.png';
export default {
data() {
return {
msg: 'Hello Vue1',
url: logo,
};
},
methods: {
fetchData() {
const that = this
new Promise((resovle) => {
resovle('ok')
}).then(res => {
console.log(res)
that.msg = res
})
}
},
created() {
this.fetchData();
},
};
</script>
<style>
.example {
color: red;
}
</style>
7. 设置 src 别名以及省略后缀
webpack.config.js
resolve: {
extensions: [".vue", ".js"],
alias: {
"@": path.resolve(__dirname, "src"),
},
},
测试文件添加 src\main.js
// App.vue 引入
import App from "@/App.vue";
项目强化支持
1. 支持less
安装依赖
yarn add less less-loader --dev
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: ["vue-style-loader", "style-loader", "css-loader", "less-loader"],
},
],
},
};
2. 生产环境优化: 为不同工作环境创建不同的配置
- 准备工作
touch webpack.common.js // 放置公共打包配置 touch webpack.dev.js // 放置开发环境打包配置 touch webpack.prod.js // 放置生产环境打包配置 yarn add webpack-merge --dev // 安装依赖
webpack.common.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
module.exports = {
entry: ["./src/main.js"],
output: {
filename: "[name]-[contenthash:8].bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
},
{
test: /.css$/,
use: ["vue-style-loader", "style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["vue-style-loader", "style-loader", "css-loader", "less-loader"],
},
{
test: /.(png|jpe?j|gif|svg)(\?.*)?$/,
use: {
loader: "url-loader",
options: {
limit: 10 * 1024, // 10 KB
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "public/index.html", // 模板地址
filename: "index.html",
title: "vue demo", // title
favicon: "public/favicon.ico", // 图标
}),
new VueLoaderPlugin(),
],
resolve: {
extensions: [".vue", ".js"],
alias: {
"@": path.resolve(__dirname, "src"),
},
},
};
webpack.dev.js
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "development",
devServer: {
contentBase: path.join(__dirname, "dist"), // html所在路径
compress: true, // 是否压缩
port: 3000, // 端口
hot: true, // 热部署
open: true, // 打包完成后自动打开网页
},
});
webpack.prod.js
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = merge(common, {
mode: "production",
plugins: [new CleanWebpackPlugin()],
});
package.json
"scripts": {
"dev": "webpack --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"serve": "webpack serve --config webpack.dev.js"
},
执行命令
rm webpack.config.js
删除原配置文件
使用命令yarn build
yarn serve
yarn dev
测试当前设置是否成功
3. SourceMap
说明: 生产环境下不推荐开启sourcemap,如果有相应需求建议使用
nosources-source-map
webpack.dev.js
devtool: "eval-cheap-module-source-map",
4. Tree Shaking
这里的优化功能(压缩等)都放在该模块下一起书写
webpack.common.js
module.exports = {
optimization: {
usedExports: true,
concatenateModules: true,
minimize: true,
},
}
5. 公共模块提取
webpack.common.js
module.exports = {
optimization: {
splitChunks: {
chunks: "all", // 自动提取所有公共模块到单独 bundle
},
},
}
项目ESlint配置
准备工作
yarn add eslint eslint-loader --dev // 安装相应依赖
yarn run eslint --init // 初始化eslint配置文件
配置
webpack.common.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "eslint-loader",
exclude: /node_modules/,
enforce: "pre",
},
],
},
}
通过Git Hooks在代码提交前强制lint
yarn add husky lint-staged --dev // 安装
package.json
"scripts": {
"dev": "webpack --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"serve": "webpack serve --config webpack.dev.js",
"precommit": "lint-staged"
},
"husky": {
"hooks": {
"pre-commit": "npm run precommit"
}
},
"lint-staged": {
"*.js": [
"eslint",
"git add"
]
},