上一文中做了一个基本的Webpack环境搭建,对于webpack+vue组合的搭建过程,网上搜索资料不少,好好研究任意一篇就可以掌握原理和过程,本文没有利用vue-cli脚手架工具搭建,而是自己动手基于webpack环境导入vue项目。
实战如下:(实际执行过程中碰见不少坑,都研究后解决了,大概的步骤记录下来,供参考)
1:基本的webpack环境搭建:引入模块:css-loader,style-loader,webpack, webpack-dev-server等,对照Webpack环境搭建;
2:npm i -D vue-loader;//解析转化.vue文件,
npm i -D vue-template-complier //将vue-loader提取出的html模板编译成js代码;
3:npm i -S vue;
-D 保存在pakage.json文件的devDependencies节点;-S保存在dependencies节点下;
由于vue项目采用了ES6语法, 需要接入Babel 转化浏览器可以识别的ES5语法
4: Babel需要引入下面的模块
babel-plugin-transform-runtime //Babel转化插件
babel-runtime//上面的插件依赖runtime
babel-core babel-loader //当前webpack引入babel必须依赖的模块
babel-preset-env //presets 预设:告诉babel使用了何种ES6语法特性;env 为包含当前最新特性;
实际配置的package.json如下;
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-plugin-runtime": "^1.0.7",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"css-loader": "^2.1.1",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"html-webpack-plugin": "^3.2.0",
"style-loader": "^0.23.1",
"vue-loader": "^15.7.0",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
},
"dependencies": {
"vue": "^2.6.10"
}
采坑经验: 上面的安装不要一会是npm 一会是cnpm,会导致版本不兼容,编译失败
5:npm run dev 运行:
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
加入 VueLoaderPlugin即可,如下所示:webpack.config.js配置为:
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports= {
... //省略其他配置
plugins: [
new VueLoaderPlugin()
]
}
6: 到这里,开发一个.vue单组件页面,然后通过import xx from '/xx.vue',最简单vue项目就可进行了,但实际项目中远非如此,涉及到优化,打包等诸多环节,下面再来一个一个问题解决;
7:区分开发和生产环境
webpack.base.config.js内容为:
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const ExtractTextPlugin = require ('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require ('html-webpack-plugin');
module.exports= {
entry: path.resolve(__dirname,"../src/main.js"),
output: {
filename:'[name]_[hash:8].js',
chunkFilename: '[id].[chunkhash].js',
path:path.resolve(__dirname,"../dist"),
},
module: {
rules: [{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.css$/,
loader:ExtractTextPlugin.extract({
fallback:'style-loader',
use:'css-loader',
publicPath:"../dist"
})
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
]
},
resolve: {
extensions: ['.vue', '.js', '.json']
},
plugins: [
new VueLoaderPlugin(),
new ExtractTextPlugin({
filename:'assest/[name]_[hash:8].css', //打包后的文件路径以及文件名
}),
new HtmlWebpackPlugin ({
template: path.resolve (__dirname, '../index.html')
}),
]
}
webpack.dev.config.js内容为:
需要先npm i -D webpack-merge
const merge = require('webpack-merge');
const base = require('./webpack.base.config');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
var config = {
devtool: 'source-map',
devServer: {
quiet: true,
overlay: true,
},
plugins: [
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: ['You application is running here http://localhost:8080'],
},
clearConsole: true,
})
]
}
module.exports= merge(base,config)
webpack.prod.config.js内容为:
const merge = require('webpack-merge');
const base = require('./webpack.base.config');
const DefinePlugin = require ('webpack/lib/DefinePlugin');
module.exports= merge(base,{
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
query:{ // 解决error: Unexpected token: punc (()
presets:['es2015']
},
exclude: /node_modules/
},
]
},
mode: 'production',
plugins: [
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
]
})
package.json配置中script节点如下:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.config.js",
"build": "webpack --config build/webpack.prod.config.js"
},
开发测试:npm run dev
打包发布:npm run build 可以看到输出为:
7:JS、CSS 压缩处理
在第6步中设置了 mode='production' webpack自动对js压缩了,但css未被压缩处理,这里使用optimize-css-assets-webpack-plugin插件来压缩优化处理:
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
optimization: {
minimizer: [new OptimizeCssAssetsPlugin({})],
},
plugins: [
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
})
]
8:css 中引用图片的处理:
此处不经意就会碰到404的错误:资源找不到,多半是引用路径导致的。本人在此也折腾了一会:
在实战的这个小例子中:保持开发css引用的图片路径和打包输出的路径目录结果保持一致,我把这个目录结果调整了下:
最终结果如下图所示:
使用file-loader+url-loader 模块加载图片,并调整下webpack.base.config.js的相关位置:
module: {
rules: [
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 1024*30,// 当文件大小小于limit byte时会把图片转换为base64编码的dataurl,否则返回普通的图片
name: 'assest/images/[name]-[hash:5].[ext]', // 图片文件名称加上内容哈希
fallback: 'file-loader',
publicPath:"../../",
}
}]
}
]
},
注意上图中 publicPath的处理为相对路径。
写一个css测试如下:
<template>
<div class="bg-main">
<dcstop></dcstop>
</div>
</template>
<style scoped>
.bg-main
{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background-image: url('./assest/images/monitorbg.png');
background-repeat: no-repeat;
}
</style>
上面一个大的背景图片,下面是一个小图片的url,可以看到url-loader的处理base64编码后的字符串;
经过一通上面的操作,解决了webpack vue的导入,开发和正式环境的区分,含基本的优化:js压缩,css压缩等,也解决了图片资源的路径问题,还差一个css的预处理。这里选择本人比较喜欢的stylus
9: CSS预处理的支持:这里选用stylus:
cnpm i -D stylus stylus-loader
{
test: /\.styl(us)?$/,
use: [
'style-loader',
'css-loader',
'stylus-loader'
]
},
注意上面的正则表达式,如果写成 test: /\.styl$/ 就报错:
Module parse failed: Unexpected character
You may need an appropriate loader to handle this file type
所以碰见问题,一定不要被问题吓倒了,先尝试根据错误去分析下问题的大概原因,并去相关官网搜索关键字或百度关键字,事物之间都有千丝万缕的联系,从别人的说法中,可以一层一层去找问题问题,只要功夫到位,问题一定会解决。
本文完。
附加一份完整的webpack.dev.config.js配置项:
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const ExtractTextPlugin = require ('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require ('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports= {
entry: path.resolve(__dirname,"../src/main.js"),
output: {
filename:'[name]_[hash:8].js',
chunkFilename: '[id].[chunkhash].js',
path:path.resolve(__dirname,"../dist"),
publicPath: '/'
},
module: {
rules: [{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.css$/,
loader:ExtractTextPlugin.extract({
fallback:'style-loader',
use:'css-loader',
publicPath:"../dist"
})
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.styl(us)?$/,
use: [
'style-loader',
'css-loader',
'stylus-loader'
]
},
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 1024*30,// 当文件大小小于limit byte时会把图片转换为base64编码的dataurl,否则返回普通的图片
name: 'assest/images/[name]-[hash:5].[ext]', // 图片文件名称加上内容哈希
fallback: 'file-loader',
publicPath:"../../",
}
}]
}
]
},
resolve: {
extensions: ['.js', '.json','.vue','.styl']
},
plugins: [
new VueLoaderPlugin(),
new ExtractTextPlugin({
filename:'assest/style/[name]_[hash:8].css', //打包后的文件路径以及文件名
}),
new HtmlWebpackPlugin ({
template: path.resolve (__dirname, '../index.html')
}),
new CleanWebpackPlugin({
root: path.resolve(__dirname, '../dist'), //根目录
}),
]
}