自己配置webpack4.x vue开发/生产环境

先上配置文件吧~
package.json

{
  "name": "vuewebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --mode development --profile --progress",
    "build": "cross-env NODE_ENV=production webpack --mode production --profile --progress"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^8.6.5",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-0": "^6.24.1",
    "babel-runtime": "^6.26.0",
    "clean-webpack-plugin": "^0.1.19",
    "cross-env": "^5.2.0",
    "css-loader": "^0.28.11",
    "file-loader": "^1.1.11",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "image-webpack-loader": "^4.3.1",
    "mini-css-extract-plugin": "^0.4.1",
    "postcss-loader": "^2.1.6",
    "poststylus": "^1.0.0",
    "px2rem2-loader": "^1.0.2",
    "style-loader": "^0.21.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.2",
    "url-loader": "^1.0.1",
    "vue-hot-reload-api": "^2.3.0",
    "vue-html-loader": "^1.2.4",
    "vue-loader": "^15.3.0",
    "vue-style-loader": "^4.1.1",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.5"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "vue": "^2.5.17",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  }
}

然后是我的目录结构
在这里插入图片描述

1.生成package.json
打开git bash
新建一个项目文件夹
mkdir vue-webpack
cd vue-webapck
npm init

然后就会看到你的文件夹下有
package.json

2.配置webpack.config.js
1.获取环境变量

const isProd = process.env.NODE_ENV === 'production';

下面会根据开发或生产环境进行不同的配置;

2.设置入口文件
entry: {
main: ‘./src/main.js’, // 入口文件
vendor: [‘axios’] // 打包第三方库放在vendor.js中
},

3.既然有入口,就应当有出口

const path = require('path')


...
 output: {
        path: path.resolve(__dirname, 'dist'), // 打包目录
        filename: isProd?'javascript/[name].[hash:8].js':'[name].js', // [name] 是entry的key
        publicPath: isProd?'./':'/'
    },

4.开发环境启用source-map

    devtool: isProd?false:'eval-source-map', // 开启sourc-map可以查看报错的位置

如果你不知道source-map的作用
请戳 https://blog.csdn.net/qq_40126542/article/details/81097551
找到报错的源文件

5.配置module.rules,
注意webpack4.x中module写法和前面版本有点小区别
文本分离插件在webpack3.x之前试用的extract-text-webpack-plugin,现在webpack4.x版本建议使用mini-css-extract-plugin

const MiniCssExtractPlugin=require('mini-css-extract-plugin'); // 文本分离插件,分离js和css
/**
 *  css和stylus开发、生产依赖
 *  生产分离css
 * 
 */
const cssConfig=[isProd?MiniCssExtractPlugin.loader:'vue-style-loader',{
        loader: 'css-loader',
        options: {
            minimize: isProd,
            sourceMap: !isProd
        }
    },'postcss-loader']
    ,stylusConfig=[isProd?MiniCssExtractPlugin.loader:'vue-style-loader',{
        loader: 'css-loader',
        options: {
            minimize: isProd,
            sourceMap: !isProd
        }
    },{
        loader: 'stylus-loader',
        options: {
            sourceMap: !isProd
        }
    }];
{...}
module: {
        rules: [
            {
                test: /\.css$/,
                use:cssConfig
            },
            {
                test: /\.styl(us)?$/,
                use: stylusConfig
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    hotReload: true, // 热重载
                    loaders:{
                        css: cssConfig,
                        stylus: stylusConfig
                    }
                },
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                query:{
                    presets: ['env']
                },
                exclude: file => (
                    /node_modules/.test(file) &&
                    !/\.vue\.js/.test(file)
                )
            },
            {
                test: /\.(png|jpe?g|gif|bmp|svg)$/,
                use: [{
                    loader: 'url-loader',
                    options: { // 配置图片编译路径
                        limit: 8192, // 小于8k将图片转换成base64
                        name: '[name].[hash:8].[ext]',
                        outputPath: 'images/'
                    }
                },{
                    loader: 'image-webpack-loader', // 图片压缩
                    options: {
                        bypassOnDebug: true
                    }
                }]
            },
            {
                test: /\.html$/,
                use: [{
                    loader: 'html-loader',
                    options: { // 配置html中图片编译
                        minimize: true
                    }
                }]
            },
            {test: /\.(mp4|ogg|svg)$/,use: ['file-loader']},
            {
                test:/\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader:'url-loader',
                options:{
                    limit:8192,
                    name:'fonts/[name].[hash:8].[ext]'
                }
            }
        ]
}
{...}

6.配置开发模式热启动

{...}
devServer:isProd?{}:{
        contentBase: path.join(__dirname, 'dist') // 将 dist 目录下的文件,作为可访问文件。
        ,compress: true // 开启Gzip压缩
        ,host: 'localhost' // 设置服务器的ip地址,默认localhost
        ,port: 9001 // 端口号
        ,open:true // 自动打开浏览器
}
{...}

7.配置引入文件不用带后缀和路径别名

resolve: {
        extensions: ['.js', '.vue', '.styl'], // import引入文件的时候不用加后缀
        modules: [ // 配置路径别名
            'node_modules'
            ,path.resolve(__dirname, 'src/components')
            ,path.resolve(__dirname, 'src/assets')
        ],
        alias: {
            vue: 'vue/dist/vue.js',
        }
    },

注意此处有个坑
vue-loader需要

const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器

以及resolve里添加

alias: {
            vue: 'vue/dist/vue.js',
        }

8.插件

const webpack=require('webpack');
const HtmlWebpackPlugin=require('html-webpack-plugin'); // 自动生成index.html
const CleanWebpackPlugin=require('clean-webpack-plugin'); // 清理垃圾文件

const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue加载器
const PostStylus=require('poststylus'); // stylus加前缀
{...}
plugins: [
        new VueLoaderPlugin(), // vue加载器
        new webpack.BannerPlugin(`xs build at ${Date.now()}`), // 打包后在.js/.css页头的时间(并没什么卵用)
        new CleanWebpackPlugin([path.join(__dirname, isProd?'dist':'')]), // 每次打包之前清理打包目录
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'src/index.html') // 引入模版
            ,favicon: path.join(__dirname, 'src/assets/icon/favicon.ico')
            ,filename: 'index.html'
            ,minify: { // 对index.html压缩
                collapseWhitespace: isProd // 去掉index.html的空格
                ,removeAttributeQuotes: isProd // 去掉引号
            }
            ,hash: true // 去掉上次浏览器的缓存(使浏览器每次获取到的是最新的html)
        }),
        new MiniCssExtractPlugin({ // 分离css
            filename: isProd?'stylesheets/[name].[hash:8].css':'[name].css',
            allChunks: true
        }),
        new webpack.NamedModulesPlugin(), // 热更新 HMR
        new webpack.HotModuleReplacementPlugin(), // 热加载插件 HMR
        new webpack.LoaderOptionsPlugin({ // stylus加前缀
            options: {
                stylus: {
                    use: [
                        PostStylus(['autoprefixer']),
                    ]
                },
                babel: {
                    presets: ['es2015'],
                    plugins: ['transform-runtime']
                }
            }
        }),
        new webpack.ProvidePlugin({ // 配置第三方库
            $http: 'axios' // 在.vue文件中可以使用$http发送请求,不用每次都import Axios from 'axios';也不用挂载到vue原型链上
        })
    ]
{...}

webpack都有哪些插件?
.)html生成插件: html-webpack-plugin
2.)css分离的插件:extract-text-webpack-plugin new extractTextPlugin(“css/index.css”) //这里的/css/index.css 是分离后的路径
3.)处理HTML中的图片:html-withimg-loader
4.)自动处理CSS3属性前缀:postcss-loader 和 autoprefixer
5.)消除未使用的css 和js: purify-css purifycss-webpack
6.)copy 插件 :copy-webpack-plugin
7.)编译输出文件前,删除旧文件: clean-webpack-plugin
8.) 压缩css,优化css结构,利于网页加载和渲染 : optimize-css-assets-webpack-plugin
9.) 打包编译时,显示进度条: progress-bar-webpack-plugin
10.) 规范scss, less,css书写规则:stylelint-webpack-plugin
11.) 将CSS解压到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件:webpack4用mini-css-extract-plugin 代替了 extract-text-webpack-plugin
12.)减少构建时间:webpack-parallel-uglify-plugin
13.)加快编译速度:happypack
14.)资源路径与问件名对应:assets-webpack-plugin

自动处理CSS3属性前缀:postcss-loader 和 autoprefixer

消除未使用的CSS 安装PurifyCSS-webpack

urifyCSS-webpack要依赖于purify-css这个包,所以两个都要下载
npm install purifycss-webpack purify-css --save-dev
因为我们需要同步检查html模板,所以我们需要引入node的glob对象使用。在webpack.dev.config.js文件头部引入glob
const glob = require('glob');
const PurifyCSSPlugin = require("purifycss-webpack");
new PurifyCSSPlugin({
//这里配置了一个paths,主要是需找html模板,purifycss根据这个配置会遍历你的文件,查找哪些css被使用了。
paths: glob.sync(path.join(__dirname, 'src/*.html')),
}),

webpack bable 的配置;

npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
//babel 配置
{
test:/.(jsx|js)$/,
use:{
loader:'babel-loader',
options:{
presets:[
"es2015","react"
]
}
},
exclude:/node_modules/
}
5.1)一般是写到.babelrc 文件夹里
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-0"
]
}
5.2)对比.webpack.dev.config.js里的loader配置
babel 配置
{
test:/.(jsx|js)$/,
use:{
loader:'babel-loader',
},
exclude:/node_modules/
}

9.实现vue中的css module
题外话:
scoped和css module的异同?
相同点
均为解决CSS全局作用域问题(样式冲突(污染))的一个解决方案。

不同点:
用法上:
scoped直接可以使用 在style标签添加这个属性
而css module需要css-loader配置才行

功能上:
scoped在元素中添加了一个唯一属性用来区分。
所以缺点是 如果用户在别处定义了相同的类名,也许还是会影响到组件的样式。
而且 scoped这种处理会造成每个样式的权重加重了:

css module
直接替换了类名

stylusConfig=[isProd?MiniCssExtractPlugin.loader:'vue-style-loader',{
    loader: 'css-loader',
    options: {
        minimize: isProd,
        sourceMap: !isProd,
        // 开启css modules
        module: true,
        // 自定义生成的类名
        localIdentName: '[local]_[hash:base64:8]'
    }
},
    'px2rem2-loader?remUnit=75&remPrecision=8',
    {
    loader: 'stylus-loader',
    options: {
        sourceMap: !isProd
    }
}];

顺便这里也安装了

npm install px2rem2-loader -D

作用是让px自己转为rem

  1. babel
    创建.babelrc
{
  "presets": [
    ["env", {
      "modules": false ,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-3"
  ]
}

11.配置vue相关的文件
基本和vue-cli脚手架生成的差不多

components/index.vue

<template>
    <div :class="$style.home">
        <h1>home<div :class="$style.title">hah</div></h1>
        <ul><li>hei</li></ul>
    </div>
</template>

<script>
    export default {

    }
</script>

<style lang="stylus" module>
    @import "../css/reset.styl";
    .home{
        color: red;
        font-size: 80px;
    }
</style>

这里的class是绑定的class ,使用css module 的class必须要这么写

css/reset.styl

h1
  color: pink
  font-size 50px
  .title
    color: yellow
    font-size: 100px

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/index.vue'

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/',
        name: 'home',
        component: Home
    }]
})

App.vue

<template>
    <div id="app">
        {{text}}
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app',
        data () {
            return {
                text: 'hello world'
            }
        }
    }
</script>

<style lang="stylus">

</style>

模板文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>自定义模板</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import 'babel-polyfill'


Vue.config.productionTip = false

new Vue({
    el: '#app',
    router,
    components: {
        App
    },
    template: "<App></App>"
})

参考
https://www.jianshu.com/p/87b48e29773c

https://www.cnblogs.com/panax/p/9314396.html

猜你喜欢

转载自blog.csdn.net/onepunchmen00/article/details/85493202