• webpack4搭建Vue开发环境笔记~~持续更新


    项目git地址

    一、node知识

    __dirname: 获取当前文件所在路径,等同于path.dirname(__filename)

    
    console.log(__dirname);
    // Prints: /Users/mjr
    console.log(path.dirname(__filename));
    // Prints: /Users/mjr
    

    path.resolve([..paths]): 把一个路径或路径片段的序列解析为一个绝对路径

    • 给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径
    • 如果处理完全部给定的 path 片段后还未生成一个绝对路径,则当前工作目录会被用上
    • 生成的路径是规范化后的,且末尾的斜杠会被删除,除非路径被解析为根目录
    • 长度为零的 path 片段会被忽略
    • 如果没有传入 path 片段,则 path.resolve() 会返回当前工作目录的绝对路径
    
    path.resolve('/foo/bar', './baz');
    // 返回: '/foo/bar/baz'
    
    path.resolve('/foo/bar', '/tmp/file/');
    // 返回: '/tmp/file'
    
    path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
    // 如果当前工作目录为 /home/myself/node,
    // 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
    

    二、配置最基本的webpack

    项目目录生成如下文件

    
    .
    ├── build
    │   ├── build.js
    │   ├── index.html
    │   ├── webpack.base.conf.js
    │   ├── webpack.dev.conf.js
    │   └── webpack.prod.conf.js
    ├── package.json
    ├── package-lock.json
    └── src
        ├── App.vue
        ├── main.js
        ├── timg.gif
        └── timg.jfif
    

    首先,先装下webpack依赖:

    
    npm i webpack webpack webpack-cli -D
    

    1、webpack.base.conf.js

    
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
      entry: {
        bundle: path.resolve(__dirname, '../src/main.js')
      },
      output: {
        path: path.resolve(__dirname, '../dist'),
        filename: '[name].[hash].js',
        publicPath: '/'
      },
      module: {
        rules: [
          
        ]
      },
      plugins: [
        <!-- 以当前目录的index.html为模板生成新的index.html,这个插件就是将新生成的文件(js,css)引入 -->
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, 'index.html')
        })
      ],
      resolve: {
        
      }
    };
    

    上面用到了html-webpack-plugin插件,装下:

    
    npm i html-webpack-plugin -D
    

    2、webpack.dev.conf.js

    
    const merge = require('webpack-merge');
    const path = require('path');
    const baseConfig = require('./webpack.base.conf');
    module.exports = merge(baseConfig, {
      // mode关系到代码压缩质量  https://webpack.docschina.org/guides/tree-shaking/
      mode: 'development',
      // source-map,将编译后的代码映射到原代码,便于报错后定位错误
      devtool: 'inline-source-map',
      <!-- webpack-dev-server配置项 -->
      devServer: {
        <!-- devserver启动服务的根路径 -->
        contentBase: path.resolve(__dirname, '../dist'),
        <!-- 打开浏览器 -->
        open: true
      }
    });
    

    合并webpack配置的插件webpack-merge,能够启一个简易服务的webpack-dev-server,详情

    
    npm i webpack-dev-server webpack-merge -D
    

    3、webpack.prod.conf.js

    
    const merge = require('webpack-merge');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const path = require('path');
    const baseConfig = require('./webpack.base.conf');
    module.exports = merge(baseConfig, {
      mode: 'production',
      devtool: 'source-map',
      module: {
        rules: []
      },
      plugins: [
        new CleanWebpackPlugin(['dist/'], {
          root: path.resolve(__dirname, '../')
        })
      ]
    });
    

    清除文件的插件:

    
    npm i clean-webpack-plugin -D
    

    4、build.js

    
    const webpack = require('webpack');
    const config = require('./webpack.prod.conf');
    
    webpack(config, (err, stats) => {
      if (err || stats.hasErrors()) {
        // 在这里处理错误
        console.error(err);
        return;
      }
      // 处理完成
      console.log(stats.toString({
        chunks: false,  // 使构建过程更静默无输出
        colors: true    // 在控制台展示颜色
      }));
    });
    

    5、npm scripts

    
    // package.json
    {
      +++
      "scripts": {
        "build": "node build/build.js",
        "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"
      },
    }
    

    以上算是一个webpack的基本结构,如果入口文件(main.js)里引入的是正经js,npm dev和npm build是可以的打包编译的,但是我们是要写vue,那就要加些loader和plugins了

    三、引入一些基本的loader

    1、babel-loader

    依赖安装要求:webpack 4.x | babel-loader 7.x | babel 6.x,注意babel-loader和babel的版本,不然会报错

    
    npm install -D babel-loader@7 babel-core babel-preset-env webpack
    

    然后再配置中加入

    
    // base.conf.js
    module.exports = {
      +++
      module: {
        rules: [
          {
            test: /.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
            }
          },
          +++
        ]
      }
    }
    

    我们还需要添加一个配置文件(.babelrc)在根目录下:

    
    /// .babelrc
    {
      "presets": [
        ["env", {
          "targets": {
            "browsers": [">0.25%", "last 2 versions", "not ie 11", "not op_mini all"]
          }
        }]
      ]
    }
    

    这就是 babel-preset-env 的作用,帮助我们配置 babel。我们只需要告诉它我们要兼容的情况(目标运行环境),它就会自动把代码转换为兼容对应环境的代码。
    以上代码表示我们要求代码兼容最新两个版本的浏览器,不用兼容 11(及以下)和Opera Mini,另外市场份额超过 0.25% 的浏览器也必须支持。
    只需要告诉 babel-preset-env 你想要兼容的环境,它就会自动转换

    2、url-loader、file-loader

    如果我们希望在页面引入图片(包括img的src和background的url)。当我们基于webpack进行开发时,引入图片会遇到一些问题

    其中一个就是引用路径的问题。拿background样式用url引入背景图来说,我们都知道,webpack最终会将各个模块打包成一个文件,因此我们样式中的url路径是相对入口html页面的,而不是相对于原始css文件所在的路径的。这就会导致图片引入失败。这个问题是用file-loader解决的,file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件

    另外,如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。

    url-loader和file-loader是什么关系呢?简答地说,url-loader封装了file-loader。url-loader赖于file-loader,即使用url-loader时,也要安装file-loader

    
    npm i url-loader file-loader -D
    
    
    /// base.conf.js
    module.exports = {
      +++
      module: {
        rules: [
          +++
          {
            test: /.(png|jpg|jfif|jpeg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  // 低于这个limit就直接转成base64插入到style里,不然以name的方式命名存放
                  // 这里的单位时bit
                  limit: 8192,
                  name: 'static/images/[hash:8].[name].[ext]'
                }
              }
            ]
          },
          // 字体图标啥的,跟图片分处理方式一样
          {
            test: /.(woff|woff2|eot|ttf|otf)$/,
            use: [
              {
                loader: 'url-loader',
                name: 'static/font/[hash:8].[name].[ext]'
              }
            ]
          },
        ]
      },
    }
    

    3、vue-loader

    作用自己去看

    
    npm i vue-loader -D
    
    
    // base.conf.js
    module.exports = {
      +++
      module: {
        rules: [
          +++
          {
            test: /.vue$/,
            loader: 'vue-loader'
          }
        ]
      }
    }
    
    

    在这里还要一个插件,这个插件是必须的!

    
    // base.conf.js
    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    module.exports = {
      +++
      plugins: [
          // 它的职责是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。
          // 例如,如果你有一条匹配 /.js$/ 的规则,那么它会应用到 .vue 文件里的 <script> 块
          new VueLoaderPlugin(),
          +++
      ]
    }
    

    4、处理样式

    • less-loader: 将less转css
    • css-loader: 将css转为CommonJS规范的js字符串
    • style-loader: 将js字符串转为style node插入到html中
    • postcss-loader: PostCSS 是一个允许使用 JS 插件转换样式的工具,我们用postcss的插件就要配置它,autoprefixer就是postcss项目里的一个插件
    • autoprefixer: 添加了 vendor 浏览器前缀,它使用 Can I Use 上面的数据。
    
    npm i less-loader css-loader style-loader less autoprefixer postcss-loader -D
    
    
    const StyleLintPlugin = require('stylelint-webpack-plugin');
    // base.conf.js
    module.exports = {
      +++
      module: {
        rules: [
          {
            // less css
            test: /.l?css$/,
            // use里的loader执行顺序为从下到上,loader的顺序要注意
            // 这里检测到less/css文件后需要将后续处理loader都写在此use里,如果less和css过分开检测处理,不能说先用less-loader转成css,然后让它走/.css/里的use
            use: [
              {loader: 'style-loader'},
              {loader: 'css-loader'},
              {loader: 'postcss-loader'},
              {loader: 'less-loader'},
            ]
          },
          +++
        ]
      }
    }
    
    
    • 配置postcss
    在根目录新建个postcss.config.js文件来配置autoprefixer,通过Browerslist来帮助你配置,浏览器市场份额,了解下browserl.ist
    
    module.exports = {
      plugins: [
        require('autoprefixer')({
          "browsers": [
            "defaults",
            "not ie < 9",
            "last 2 versions",
            "> 1%",
            "iOS 7",
            "last 3 iOS versions"
          ]
        })
      ]
    }
    
    • mini-css-extract-plugin提取css
    这里打包cssless 为例,r如果要用mini-css-extract-plugin插件提取css,将上面改为如下:
    
    npm install mini-css-extract-plugin -D
    
    
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    +++
    module.exports = {
      +++
      // 模块,loader
      module: {
        rules: [
          +++
          {
            test: /.l?(c|e)ss$/,
            use: [
              MiniCssExtractPlugin.loader,
              {loader: 'css-loader'},
              {loader: 'postcss-loader'},
              {loader: 'less-loader'},
            ]
          },
          +++
        ]
      },
      // 插件
      plugins: [
        +++
        new MiniCssExtractPlugin({
          filename: 'static/css/[name].[hash].css',
          chunkFilename: 'static/css/[name].[hash].css'
        })
      ]
    }
    

    5、然后配置下别名resolve.extensions

    
    // base.conf.js
    module.exports = {
      +++
      resolve: {
        alias: {
          // 配置别名'vue$',不然import 'vue'时,webpack找不到
          'vue$': 'vue/dist/vue.esm.js',
          // 这个为src配置别名,非必需,为方便而已
          '@': path.resolve(__dirname, '../src')
        },
        // 在import这些拓展名的文件时,可以省略拓展名
        extensions: ['*', '.js', '.json', '.vue'],
      }
    }
    

    现在我们来测试以下,安装一个vue

    
    npm i vue
    

    在mian.js里面

    
    import Vue from 'vue'
    import App from './App'
    
    new Vue({
      el: '#app',
      components: {App},
      template: '<App/>'
    })
    

    在App.vue里写入

    
    <template>
      <div>
        <h3 class="title">{{title}}</h3>
        <p class="content">{{content}}</p>
        <div class="goddess">
          <div class="right">
            <h4 class="right__h4">background引入图片</h4>
            <div class="right__img"></div>
          </div>
          <div class="left">
            <h4 class="left__h4">img标签直接引入图片</h4>
            <img class="left__img" src="./timg.jfif" />
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      components: {
        Foot: Footer
      },
      data () {
        return {
          title: 'hello word',
          content: 'webpack4 搭建vue环境',
        }
      },
    }
    </script>
    
    
    <style lang="less" scoped>
      .title {
        font-size: 20px;
        text-align: center;
        color: red;
      }
      .content {
        font-size: 14px;
        color: #333333;
      }
      .goddess {
    
        .left {
          margin-left: 50%;
          &__h4 {
            font-size: 14px;
          }
          &__img {
             308px;
            height: 433px;
          }
        }
        .right {
          float: left;
          &__h4 {
            font-size: 14px;
          }
          &__img {
             300px;
            height: 150px;
            background: url('./timg.gif') no-repeat;
          }
        }
      }
    </style>
    
    

    好了,npm dev 先看一下女神,放松一下:

    在这里插入图片描述

    四、做一些优化

    1、提取公共代码

    使用 splitChucksPlugin 插件,这是 Webpack 自带的,不用安装第三方依赖,默认配置即可

    
    <!-- base.conf.js -->
    module.exports = {
      +++
      plugins: [
        +++
        new webpack.optimize.SplitChunksPlugin()
      ]
    }
    

    想了解这个插件的默认配置及如何配置,英文中文

    2、将第三方库单独打包

    每次我们对项目进行打包时,我们都会把引用的第三方依赖给打包一遍,比如 Vue、Vue-Router、React 等等。但是这些库的代码基本都是不会变动的,我们没必要每次打包都构建一次,所以我们最好将这些第三方库提取出来单独打包,这样有利于减少打包时间。
    官方插件是 DllPlugin。推荐一个比较好用的插件 —— autodll-webpack-plugin

    
    npm i autodll-webpack-plugin -D
    
    
    // base.conf.js
    module.exports = {
      +++
      plugins: [
       // 将一些不太可能改动的第三方库单独打包,会通过缓存极大提升打包速度
        new AutoDllPlugin({
          // will inject the DLL bundle to index.html
          // default false
          inject: true,
          debug: false,
          filename: '[name]_[hash].js',
          path: 'static',
          entry: {
            // [name] = vue, 在这里会将entry里的每个item(vue,jquery)都打包成一个js
            vue: [
              'vue',
              'vue-router'
            ],
            // [name] = jquery
            // jquery: [
            //   'jquery',
            //   'jquery-from'
            // ]
          }
        }),
        +++
      ]
    }
    

    inject 为 true,插件会自动把打包出来的第三方库文件插入到 HTML。filename 是打包后文件的名称。path 是打包后的路径。entry 是入口,vendor 是你指定的名称,数组内容就是要打包的第三方库的名称,不要写全路径,Webpack 会自动去 node_modules 中找到的。
    每次打包,这个插件都会检查注册在 entry 中的第三方库是否发生了变化,如果没有变化,插件就会使用缓存中的打包文件,减少了打包的时间,这时 Hash 也不会变化。

    3、热重载

    “热重载”不只是当你修改文件的时候简单重新加载页面。启用热重载后,当你修改 .vue 文件时,该组件的所有实例将在不刷新页面的情况下被替换。它甚至保持了应用程序和被替换组件的当前状态!当你调整模版或者修改样式时,这极大地提高了开发体验,以下两种方式择一即可

    
    "scripts": {
      +++
      "dev": "webpack-dev-server --hot --inline --progress --config build/webpack.dev.conf.js"
    },
    
    • 方式2:或者通过配置webpack.dev.config.js,相比第一种,就会麻烦一点
    
    const webpack = require('webpack')
    module.exports = {
      +++
      module: {
        devServer: {
          +++
          // 开启热重载
          hot: true
        },
        plugins: [
          // 启用模块热替换(HMR)
          new webpack.HotModuleReplacementPlugin(),
          // 当开启 HMR 的时候使用该插件会显示模块的相对路径,建议用于开发环境。
          new webpack.NamedModulesPlugin(),
          +++
        ]
      }
    }
    

    4、eslint

    确保 VS Code 安装了 Vetur(设置编辑器支持vue文件,如果写过vue忽略)Eslint 插件

    
    npm i -g eslint@latest
    
    eslint --init
    

    然后选个最流行的就行了

    会帮你新建一个.eslintrc.js 的配置文件以及装一些 eslint 的依赖

    在 package.json 里加上:

    
    {
      +++
      "scripts": {
        +++
        "lint": "eslint --ext .js,.vue src"
      },
    }
    

    你可以尝试的npm run lint,你会发现spacing 系列no-new.vue语法不支持等问题
    当然,你可以通过改写 lint 命令(加个--fix)来解决部分语法报错

    
    {
      +++
      "scripts": {
        +++
        "lint": "eslint --fix --ext .js,.vue src"
      },
    }
    

    或者保存的时候让 eslint 插件自动修复。 更改 VS Code 中的 eslint.autoFixOnSave 设置,勾选文本编辑->Format On Save
    当然这玩法不是我们这里的重点,安装 eslint-plugin-html 来解决vue语法eslint报错问题

    
    npm install -D eslint-plugin-html
    

    在.eslintrc.js 中配置 eslint-plugin-html

    
    module.exports = {
        +++
        "plugins": [
          // 使用eslint-plugin-html
          "html"
        ]
    };
    

    至于 main.js 里的 new 指定给变量错误 disable 掉

    
    +++
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      components: {
        App
      },
      template: '<App/>'
    })
    
    • 代码如果eslint有报错,就让编译不通过
    
    npm i eslint-loader babel-eslint -D
    
    
    <!-- .eslintrc.js -->
    {
      +++
      "parser": "babel-eslint"
    }
    
    
    
    <!-- base.config.js -->
    module.exports = {
      module: {
        rules: [
          {
            test: /.(vue|js)$/,
            loader: 'eslint-loader',
            exclude: /node_modules/,
            // 预处理
            enforce: 'pre',
            include: [path.join(__dirname, '..', 'src')]
          }
        ]
      }
    }
    
    • 代码提交之前对代码进行检查
    
    npm i husky -D 
    
    
    <!-- package.json -->
    {
      +++
      "script": {
        +++
        "precommit": "eslint --fix --ext .js --ext .vue src/"
      }
    }
    

    该工具可以在我们提交代码时,调用"precommit"钩子,执行预处理操作,eslint不通过,无法提交

    在提交时仅对git add的 js,vue 文件进行检测lint-staged 和 husky 在 pre-commit 阶段做代码检查

    
    npm i lint-staged -D
    
    
    <!-- package.json -->
    {
      +++
      "script": {
        +++
        "precommit": "lint-staged"
      },
      "lint-staged": {
        "src/**/*.{js,vue}": [
          "eslint --fix",
          "git add"
        ]
      },
    }
    

    5、引入jquery shimming

    
    npm i juery -D
    
    
    <!-- base.config.js -->
     module.exports = {
       +++
       plugins: [
         +++
         new webpack.ProvidePlugin({
           $: 'jquery'
         })
       ]
      };
    

    这样就可以将$当全局变量使用了,当然eslint要配置个global,这里不介绍了

    对你有帮助的话点个刷波6,点个赞吧

    原文地址:https://segmentfault.com/a/1190000016972438

  • 相关阅读:
    布隆过滤器原理与应用场景
    【转】程序员的世界真的很难懂~
    IDEA 2019.2.4 破解安装教程
    【转】只有程序员才能看得懂的段子
    Linux 正则表达式
    【转】雷军做程序员时写的博客,很强大!
    如何同步 Linux 集群系统时间
    百度共享云盘
    Shell 脚本 test 命令详解
    Linux 命令大全
  • 原文地址:https://www.cnblogs.com/lalalagq/p/10124626.html
Copyright © 2020-2023  润新知