2019-03-25

使用Webpack4从0搭建Vue开发环境

深入浅出webpack
webpack4 搭建 Vue 开发环境笔记

node知识

__dirname是node执行环境中的一个属性,表示当前文件所在的路径(不包含文件名称),新建一个 test.js

const path = require('path')
console.log(__dirname)
console.log(__filename)
console.log(path.dirname(__filename))

执行 node test.js

/root
/root/test.js
/root

path.resolve([...paths]) 将路径或路径片段的序列解析为绝对路径。给定的路径序列从右到左进行处理,每个后续的 path 前置,直到构造出一个绝对路径。如果没有传入 path 片段,则 path.resolve() 将返回当前工作目录的绝对路径。直接node进入命令行测试

> path.resolve() 
  '/root'
> path.resolve('/foo/bar','temp')
  '/foo/bar/temp'
>  path.resolve('/foo/bar','../temp')
  '/foo/temp'
> path.resolve('/foo/bar','/test','temp')
  '/test/temp'
>

步骤

.
├── 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
  1. 新建webpack4文件夹,然后进入,执行 npm init
  2. npm i webpack webpack webpack-cli -D
  3. npm i html-webpack-plugin -D
    html-webpack-plugin 将打包后的js、css文件引入到html
  4. npm i webpack-dev-server webpack-merge -D
    webpack-dev-server 小型的开发服务器,有热更新
  5. npm i clean-webpack-plugin -Dclean-webpack-plugin清楚build生成的目录
  6. npm install -D babel-loader@7 babel-core babel-preset-env
  7. npm i url-loader file-loader -D
    url-loader 将比较小的图片转换为base64
    file-loader 将引入的文件解析为url
  8. npm i vue-loader vue-template-compiler -D
    vue-loader解析.vue文件,需要配合vue-template-compiler
    vue-template-compiler将.vue文件中的html模板转换为render函数
  9. npm i less-loader css-loader style-loader less autoprefixer postcss-loader -D
    css-loader 是允许在js中import一个css文件,会将css文件当成一个模块引入到js文件中
    style-loader 能够在需要载入的html中创建一个<style></style>标签,标签里的内容就是CSS内容
    npm install mini-css-extract-plugin -D
  10. npm i vue
  11. npm i -g eslint@latest
    eslint --init
    npm install -D eslint-plugin-html
  12. npm i eslint-loader babel-eslint -D
  13. npm i autodll-webpack-plugin -D
  14. npm i husky -Dnpm i lint-staged -D

package.json

{
  "name": "webpack4",
  "version": "1.0.0",
  "description": "webpack test",
  "main": "index.js",
  "scripts": {
    "build": "node build/build.js",
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.5.0",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^2.0.1",
    "css-loader": "^2.1.1",
    "file-loader": "^3.0.1",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.9.0",
    "less-loader": "^4.1.0",
    "mini-css-extract-plugin": "^0.5.0",
    "postcss-loader": "^3.0.0",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "vue-loader": "^15.7.0",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.2.1",
    "webpack-merge": "^4.2.1"
  },
  "dependencies": {
    "vue": "^2.6.10"
  }
}

webpack.base.conf.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  entry: {
    bundle: path.resolve(__dirname, '../src/main.js')
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].[hash].js',
    publicPath: '/'
  },
  module: {
    rules: [
      //
      {
        test: /\.l?(c|e)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader'
          },
          {
            loader: 'less-loader'
          },
          {
            loader: 'postcss-loader'
          }
        ]
      },
      //
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      //
      {
        test: /\.(png|jpg|jfif|jpeg|gif|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: 'static/images/[hash:8].[name].[ext]'
            }
          }
        ]
      },
      //
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'url-loader',
          }
        ]
      },
      //
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'index.html')
    }),
    new MiniCssExtractPlugin({
      filename: 'static/css/[name].[hash:8].css',
      chunkFilename: 'static/css/[name].[hash:8].css'
    })
  ],
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': path.resolve(__dirname, '../src')
    },
    extensions: ['*', '.js', '.json', '.vue'],
  },
}

webpack.dev.conf.js

const merge = require('webpack-merge')
const path = require('path')
const baseConfig = require('./webpack.base.conf1')
const webpack = require('webpack')

module.exports = merge(baseConfig,{
  mode:'development',
  devtool: 'inline-source-map',
  devServer:{
    contentBase:path.resolve(__dirname,'../dist'),
    open:true,
    hot:true,
  },
  plugins:[
     // 启用模块热替换(HMR)
     new webpack.HotModuleReplacementPlugin(),
     // 当开启 HMR 的时候使用该插件会显示模块的相对路径,建议用于开发环境。
     new webpack.NamedModulesPlugin(),
  ]
})

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: [
    // 每次build的时间清掉旧的dist文件夹
    new CleanWebpackPlugin()
  ]
});

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: true, 
  }));
});