搭建前端框架:Vue2+Webpack5+tailwindcss2

前言

近期要做一个新的项目,本来打算用vue3+webpack+tailwindcss3搭建一套前端的开发框架,然而在搭建的时候遇到各种依赖包的版本兼容问题。最后还是用的vue2+webpack5+tailwindcss2。虽然都不是最新的版本,但主要是能使用,满足需求。
由于最新的tailwind css使用post css 8版本,vue2框架暂时还不支持,所以需要指定安装postcss7的版本

1
2
3

npm install tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

主要代码

package.json内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
{
"name": "test",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
"prod": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
},
"dependencies": {
"@tailwindcss/postcss7-compat": "^2.2.17",
"vue": "2.7.16",
"axios": "^0.27.2",
"core-js": "^3.6.5",
"moment": "^2.29.3",
"nativeshare": "^2.1.5",
"vue-infinite-loading": "^2.4.5",
"vue-router": "3.6.5",
"vue-toast-notification": "^0.6.2",
"less-loader": "^11.0.0",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/eslint-parser": "^7.18.2",
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "~4.5.12",
"@vue/compiler-sfc": "^3.2.37",
"autoprefixer": "^9.8.8",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.5",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^0.28.8",
"css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"eslint-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.5.0",
"image-minimizer-webpack-plugin": "^3.2.3",
"imagemin": "^8.0.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"mini-css-extract-plugin": "^2.6.0",
"postcss": "^7.0.39",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "6.7.2",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"style-loader": "^3.3.1",
"stylus-loader": "^7.0.0",
"terser-webpack-plugin": "^5.3.3",
"thread-loader": "^3.0.4",
"vue-loader": "15",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.73.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.2"
}
}

 

webpack.config.js 内容

注意这个地方是与官方文档上不同的地方,官方是创建一个postcss.config.js然后加入下面的内容,但是webpack需要到这里添加,不需要创建postcss.config.js
options: {
plugins: loader => [
require(‘tailwindcss’),//这里是关键点
require(‘autoprefixer’),
require(‘postcss-preset-env’),
],
},

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/**
* 合并dev和prod两种环境的配置
* @type {path.PlatformPath | path}
*/
const path = require('path');
const EslintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//提取css为单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");//压缩css文件
const TerserWebpackPlugin = require("terser-webpack-plugin");//压缩js文件
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");//压缩图片
const CopyPlugin = require("copy-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
const isProduction = process.env.NODE_ENV === 'production'

//返回处理样式loader函数
const getStyleLoaders = (pre) => {
return [
isProduction ? MiniCssExtractPlugin.loader : "vue-style-loader",//提取css为单独文件
"css-loader",
{
loader: 'postcss-loader',//处理css兼容,配合package.json中的browserslist来置顶兼容性
options: {
plugins: loader => [
require('tailwindcss'),//这里是关键点
require('autoprefixer'),
require('postcss-preset-env'),
],
},
},
pre && {
loader:pre,
options:pre==='less-loader'?{
// antd的自定义主题
lessOptions: {
modifyVars: {
// 其他主题色:https://ant.design/docs/react/customize-theme-cn
"@primary-color": "#1DA57A", // 全局主色
},
javascriptEnabled: true,
},
}:{}
}
].filter(Boolean);
}

module.exports = {
//入口文件
entry: './src/main.js',
output: {
path: isProduction ? path.resolve(__dirname, "../dist") : undefined,
filename: isProduction ? 'static/js/[name].[contenthash:10].js' : 'static/js/[name].js',
chunkFilename: isProduction ? 'static/js/[name].[contenthash:10].chunk.js' : 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[hash:10][ext][query]',
publicPath: '/', //配置绝对路径(原来是static,加上后变成/static),不然嵌套路由刷新会出现路径不正确导致js文件无法加载。historyApiFallback同步需要修改
clean: true,
},
module: {
rules: [
//处理css
{
test: /\.css$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: "asset",//asset可以转base64
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, //小于10kb的图片采用base64
}
}
},
//处理其他资源
{
test: /\.(woff2?|ttf)$/,
type: "asset/resource", //asset/resource不能转base64,只会原封输出
},
//处理js babel
{
test:/\.js$/,
include:path.resolve(__dirname,'../src'),
use: [
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
{
loader:'babel-loader',
options:{
cacheDirectory:true,//开启缓存
cacheCompression:false,//不做压缩,这样速度更快,只是体积大,不影响
}
}
],

},
// vue-loader不支持oneOf
{
test: /\.vue$/,
loader: "vue-loader", // 内部会给vue文件注入HMR功能代码
options: {
// 开启缓存(第二次打包更快)
cacheDirectory: path.resolve(
__dirname,
"node_modules/.cache/vue-loader"
),
},
},
],
},
plugins: [
new EslintWebpackPlugin({
context: path.resolve(__dirname, '../src'),
exclude: "node_modules",//排除目录
cache: true,
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache'),
threads, // 开启多进程
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
isProduction && new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
// 将public下面的资源复制到dist目录去(除了index.html)
isProduction && new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
toType: "dir",
noErrorOnMissing: true, // 不生成错误
globOptions: {
// 忽略文件
ignore: ["**/index.html"],
},
info: {
// 跳过terser压缩js
minimized: true,
},
},
],
}),
new VueLoaderPlugin(),
].filter(Boolean),
mode: isProduction?'production':'development',//生产模式
devtool: isProduction?"source-map":"cheap-module-source-map",//运行时可以看到代码错误,定位到行与列
//为了防止打包的时候,不把文件打包到一个文件中,配置splitChunks
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
// layouts通常是admin项目的主体布局组件,所有路由组件都要使用的
// 可以单独打包,从而复用
// 如果项目中没有,请删除
// layouts: {
// name: "layouts",
// test: path.resolve(__dirname, "../src/layouts"),
// priority: 40,
// },
// 如果项目中使用antd,此时将所有node_modules打包在一起,那么打包输出文件会比较大。
// 所以我们将node_modules中比较大的模块单独打包,从而并行加载速度更好
// 如果项目中没有,请删除
antd: {
name: "chunk-antd",
test: /[\\/]node_modules[\\/]antd(.*)/,
priority: 30,
},
// 将vue相关的库单独打包,减少node_modules的chunk体积。
vue: {
name: "vue",
test: /[\\/]node_modules[\\/]vue(.*)[\\/]/,
chunks: "initial",
priority: 20,
},
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10, // 权重最低,优先考虑前面内容
chunks: "initial",
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
//是否需要压缩
minimize:isProduction,
// 压缩的操作
minimizer: [
new CssMinimizerPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", {interlaced: true}],
["jpegtran", {progressive: true}],
["optipng", {optimizationLevel: 5}],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
},

devServer: {
open: true,
host: "localhost",
port: 7000,
hot: true,
compress: true,
historyApiFallback: {
index: '/'
}, // 解决 刷新404问题
proxy:{
'/api': {
// target: 'http://47.119.194.94:8001',
target: 'http://localhost:8001',
pathRewrite: {'': ''},
// ws: true, //用于支持websocket
// changeOrigin: true //用于控制请求头中的host值
},
}
},
//webpack解析模块加载选项
resolve: {
extensions: [".vue", ".js", ".json"], // 自动补全文件扩展名
alias: {
// 路径别名
"@": path.resolve(__dirname, "../src"),
},
},
performance: false,//关闭性能分析,提升打包速度
};

 

tailwind.config.js 内容

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
purge: ["./src/**/*.{js,jsx,vue}", "./public/index.html"],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}

 

tailwindcss.css 内容

1
2
3
4
@tailwind base;
@tailwind components;
@tailwind utilities;

 
需要到main.js引入tailwindcss.css

main.js 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router'
import VueToast from 'vue-toast-notification';
import moment from "moment";
import store from './store'
import './assets/tailwindcss.css'
Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.use(VueToast)
Vue.filter('timeFormat',function(value,str='YYYY-MM-DD HH:mm:ss'){
return moment(value).format(str)
})
new Vue({
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
},
router,
store,
}).$mount('#app')

 

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者,更多功能请访问博客站



搭建前端框架:Vue2+Webpack5+tailwindcss2
https://blog.fxcxy.com/2024/04/07/搭建前端框架-Vue2-Webpack5-tailwindcss2/
作者
spatacus
发布于
2024年4月7日
许可协议