github传送门 dev分支
webpack之二webpack部署优化
webpack之三集成vuex和vue-Router
webpack之四集成ssr
-
创建项目根目录
-
在vscode中打开, 在终端中输入
// cd到项目目录
cnpm init -y
生成package.json文件
-
安装webpack和vue, vue-loader
cnpm i webpack vue-loader webpack@3 -D
cnpm i vue -S
// 安装完成根据warning安装需要的依赖
css-loader vue-template-compiler -D
-
创建src/app.vue
<template>
<div class="text">{{text}}</div>
</template>
<script>
export default {
data () {
return {
text: 'abc'
}
}
}
</script>
<style>
.text {
color: red;
}
</style>
-
创建/webpack.config.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
}
}
-
创建/src/index.js 入口js文件
import Vue from 'vue'
import App from './app.vue'
const root = document.createElement('div')
document.body.appendChild(root)
new Vue({
render: h => h(App)
}).$mount(root)
-
安装style-loader和css-loader, url-loader, file-loader, 处理css和图片文件
cnpm i style-loader url-loader file-loader -D
url-loader依赖于file-loader
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(jpg|png|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: '[name]-kay.[ext]'
}
}
]
}
]
}
-
安装rimraf 在build之前删除dist目录
cnpm i rimraf -D
//在package.json.script中添加cli
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npm run clean && webpack --config webpack.config.js",
"clean": "rimraf dist"
},
-
嵌入stylus: 安装stylus和stylus-loader
cnpm i stylus stylus-loader -D
{
test: /\.styl$/,
use: [
'style-loader',
'css-loader',
'stylus-loader'
]
},
-
使用webpack-dev-server => 开发环境
安装cross-env区分开发环境和生产环境
配置html模板html-webpack-plugin
配置webpack全局常量插件webpack.DefinePlugin()
变更webpack.config.js结构
在package.json.script里添加dev命令
cnpm i webpac-dev-server@2 cross-env
-D
cnpm i html-webpack-plugin -D
//package.json.script
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
// 代码
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'
const config = {
target: 'web',
resolve: {
alias: {
'@assets':path.join(__dirname, 'src/assets')
}
},
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
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|png|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: '[name]-kay.[ext]'
}
}
]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"'
}
}),
new HtmlWebpackPlugin()
]
}
if (isDev) {
config.devServer = {
port: 8001,
host: '0.0.0.0',
overlay: {
errors: true
}
}
}
module.exports = config
// 终端输入 npm run dev启动项目
-
webpack-dev-server配合vue热更替功能实现
使用webpack.HotModuleReplacementPlugin和webpack.NoEmitOnErrorsPlugin
配置devServer.hot = true
css热更替使用vue-style-loader代替style-loader
if (isDev) {
config.devServer = {
port: 8001,
host: '0.0.0.0',
overlay: {
errors: true
},
hot: true
}
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
}
-
配置source-map方便调试
config.devtool = '#cheap-module-eval-source-map'
- 配置jsx和postcss
安装postcss-loader, autoprefixer babel-loader, babel-core,babel-preset-env, babel-plugin-transform-vue-jsx,babel-plugin-syntax-jsx, (babel-helper-vue-jsx-merge-props)
统一cnpm安装下
创建/.babelrc, /postcss.config.js并分别配置
// .babelrc
{
"presets":[
"env"
],
"plugins": [
"transform-vue-jsx"
]
}
// postcss.config.js
const autoprefixer = require('autoprefixer')
module.exports = {
plugins: [
autoprefixer()
]
}
// 在devServer里添加babel-loader和postcss-loader
{
test: /\.js$/,
loader: 'babel-loader'
},
{
test: /\.jsx$/,
loader: 'babel-loader'
},
{
test: /\.styl$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'stylus-loader'
]
},
-
测试jsx-vue模板
新建/src/views/test.jsx
export default {
data () {
return {
test: '这是用jsx语法写的vue模板'
}
},
render () {
return (
<div>
{this.test}
</div>
)
}
}
-
css文件分离打包成单独文件
使用extract-text-webpack-plugin
分离打包需要区分环境,删除config目录上的stylus-loader, 并在对应环境下对应loader配置
/webpack.config.js重写后配置如下
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtartTextPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'
const config = {
target: 'web',
resolve: {
alias: {
'@assets':path.join(__dirname, 'src/assets')
}
},
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.jsx$/,
loader: 'babel-loader'
},
{
test: /\.(jpg|png|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: '[name]-kay.[ext]'
}
}
]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"'
}
}),
new HtmlWebpackPlugin()
]
}
if (isDev) {
config.module.rules.push({
test: /\.styl$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'stylus-loader'
]
})
config.devtool = '#cheap-module-eval-source-map'
config.devServer = {
port: 8001,
host: '0.0.0.0',
overlay: {
errors: true
},
hot: true
}
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
} else {
config.module.rules.push({
test: /\.styl$/,
use: ExtartTextPlugin.extract({
fallback: "style-loader",
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'stylus-loader'
]
})
})
config.plugins.push(
new ExtartTextPlugin({
filename: 'style.[contenthash:8].css'
})
)
}
module.exports = config
-
单独打包类库文件, 实现缓存优化性能
修改线上环境entry选项使用options模式为js文件添加name属性app和vendor
-> 是output中[name]的由来,将开发环境的output.filename修改为'bundle.[hash:8].js',
正式环境修改为: '[name].[chunkhash:8].js'(不可以使用hash, webpack-dev-server会报错)
hash和chunkhash的区别:使用hash会让app和vendor的hash码一样是整个应用的hash(如果某个js文件改变了, 说有js文件的hash也会跟着改变, 正式环境就 没有意义了), 而chunkhash是每一个模块或者说节点单独生成hash,
使用
webpack.optimize.CommonsChunkPlugin({name: 'vendor'})
单独打包webpack相关的js代码:(好处是在有新的模块加入时候, webpack会给模块加id, 如果在中间插入会改变之前代码的id, 这样会导致hash变化破坏缓存, 需要单独打包)vendor必须在runtime之前
使用webpack.optimizeCommonsChunkPlugin({name: 'runtime'})
/webpack.config.js修改为:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtartTextPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'
const config = {
target: 'web',
resolve: {
alias: {
'@assets':path.join(__dirname, 'src/assets')
}
},
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'bundle.[hash:8].js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.jsx$/,
loader: 'babel-loader'
},
{
test: /\.(jpg|png|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: '[name]-kay.[ext]'
}
}
]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"'
}
}),
new HtmlWebpackPlugin()
]
}
if (isDev) {
config.module.rules.push({
test: /\.styl$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'stylus-loader'
]
})
config.devtool = '#cheap-module-eval-source-map'
config.devServer = {
port: 8001,
host: '0.0.0.0',
overlay: {
errors: true
},
hot: true
}
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
} else {
config.entry = {
app: path.join(__dirname, 'src/index.js'),
vendor: ['vue']
}
config.output.filename = '[name].[chunkhash:8].js'
config.module.rules.push({
test: /\.styl$/,
use: ExtartTextPlugin.extract({
fallback: "style-loader",
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
'stylus-loader'
]
})
})
config.plugins.push(
new ExtartTextPlugin({
filename: 'style.[contenthash:8].css'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime'
})
)
}
module.exports = config
-
生成环境压缩js
使用webpack.optimize.UglifyJsPlugin()并配置options.compress.warnings = false, options.output.comments: false
if(isDev) {
...
} else {
...
config.plugins.push(
new ExtartTextPlugin({
filename: 'style.[contenthash:8].css'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime'
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: false
}
})
)
}
-
生成环境压缩css
- 安装
optimize-css-assets-webpack-plugin@3
- 配置生成环境插件
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true
})
这一份简单webpack配置, 可以让vue跑起来, 但是远远不够, 接下来还会更新, 能够部署上线的配置和ssr服务器端渲染的配置
wepack从0开始配置vue环境之二: 线上部署配置优化
github地址可以下载源码来研究
网友评论