仿 vue-cli 搭建属于本身的项目

前言

前段时间学习了webpack4的相关配置, webpack4入门篇,以前的全部项目都是使用vue-cli来搭建的,恰好公司最近有个新的项目要启动,想提高本身的逼格,正好也能够巩固以前学习的webpack4的内容,决定本身用webpack来搭建一个属于本身的脚手架。css

目录结构

├── README.md
├── configs /全部的webpack配置
│   ├── util.js //webpack公用的方法工具库
│   ├── webpack.base.conf.js //基础配置
│   ├── webpack.dev.conf.js //开发配置
│   └── webpack.prod.conf.js //生产配置
├── dist //打包后的dist文件
│   ├── index.html
│   ├── logo.png
│   └── static
│       ├── css
│       │   └── 2.css
│       └── js
│           ├── 2.239af13846609eabe4c9.js
│           ├── main.4bd6023f63b0f953e5d2.js
│           └── vendor.1a84b3d307a7f4c10aad.js
├── .babelrc //babel文件配置
├── index.html //入口html文件
├── package-lock.json
├── package.json
├── src
│   ├── App.vue
│   ├── assets //css、img、js、vue组件
│   │   ├── css
│   │   ├── img
│   │   │   └── logo.png
│   │   └── js
│   ├── components
│   │   └── test.vue
│   ├── main.js //入口js文件
│   └── router //路由
│       └── index.js
└── webpack.config.js //真正使用的webpack文件	
复制代码

详细代码

关于webpack的全部配置(主要部分)

###1. webpack.base.conf.jshtml

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const util = require('./util');

module.exports = {
  entry: {
    'main': './src/main.js'
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].[hash:8].js',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        include: [path.resolve(__dirname, '../src')],
        use: [
          'vue-style-loader',
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',//为了防止css里面有引用背景图片 图片打包以后在dist/images路径错误问题
              hmr: devMode, // 仅dev环境启用HMR功能
            }
          },
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')("last 100 versions")]
            }
          }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000, //是把小于10000B的文件打成Base64的格式,写入JS
              name: util.assetsPath("images/[name]-[hash:5].[ext]"),
            }
          }
        ]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: util.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.js$/,  //es6 => es5
        exclude: /node_modules/,
        use: 'babel-loader'
      },
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.pug$/,
        oneOf: [
          // this applies to `<template lang="pug">` in Vue components
          {
            resourceQuery: /^\?vue/,
            use: ['pug-plain-loader']
          },
          // this applies to pug imports inside JavaScript
          {
            use: ['raw-loader', 'pug-plain-loader']
          }
        ]
      },

    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html', // 配置输出文件名和路径
      template: './index.html', // 配置要被编译的html文件
      favicon: './src/assets/img/logo.png', //logo
      hash: true, //是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦
    }),
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: devMode ? util.assetsPath('css/[name].css') : util.assetsPath('css/[name].[hash].css'),
      chunkFilename: devMode ? util.assetsPath('css/[id].css') : util.assetsPath('css/[id].[hash].css'),
    }),
    new VueLoaderPlugin(),
  ],
  resolve: {
    extensions: ['.vue', '.js', '.json', '.css'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@':
        path.resolve(__dirname, '..', 'src'),
      '@components':
        path.resolve(__dirname, '..', 'src/components/'),
      '@assets':
        path.resolve(__dirname, '..', 'src/assets'),
    },
  }
};	
复制代码

2. webpack.dev.conf.js

const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');

const devWebpackConfig = merge(baseWebpackConfig, {
  output:{
    publicPath: '/'
  },
  devtool: 'eval-source-map', // 指定加source-map的方式
  mode: 'development',
  devServer: {
    host: '0.0.0.0',//主机名
    port: 8080,//端口
    open: true,//自动打开浏览器
    compress: true,//服务器压缩
    hot: true,//热更新
    inline: true,//页面自动刷新
    //跨域问题
    proxy: {
      '/api': {
        target: 'https://testbi.promni.cn/v2/api',
        secure: false,
        changeOrigin: true,
        pathRewrite: {'^/api': ''}
      }
    },
  }
});

module.exports = devWebpackConfig;
复制代码

3. webpack.pro.conf.js

const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const util = require('./util');

const webpackConfig = merge(baseWebpackConfig, {
  output:{
    publicPath: './',
    filename: util.assetsPath('js/[name].[chunkhash].js')
  },
  optimization: {
    //压缩文件 mode:production 生产环境配置
    minimizer: [
      new OptimizeCssAssetsWebpackPlugin(),// 压缩css
      new UglifyJsPlugin()//压缩js
    ],
    //提取公用代码
    splitChunks: {
      cacheGroups: {
        commons: {
          // 抽离本身写的公共代码
          chunks: 'initial',
          name: 'common', // 打包后的文件名,任意命名
          minChunks: 2, //最小引用2次
          minSize: 0 // 只要超出0字节就生成一个新包
        },
        styles: {
          name: 'styles', // 抽离公用样式
          test: /\.css$/,
          chunks: 'all',
          minChunks: 2,
          enforce: true
        },
        vendor: {
          // 抽离第三方插件
          test: /node_modules/, // 指定是node_modules下的第三方包
          chunks: 'initial',
          name: 'vendor', // 打包后的文件名,任意命名
          // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
          priority: 10
        }
      }
    }
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html', // 配置输出文件名和路径
      template: './index.html', // 配置要被编译的html文件
      favicon: './src/assets/img/logo.png', //logo
      hash: true, //是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦
      minify: {
        removeAttributeQuotes: true, //去掉属性引用 删除双引号
        collapseWhitespace: true, //是否去除空格 折叠 html 为一行
        removeComments: true//去注释
      },
      chunksSortMode: 'dependency', //这个选项决定了 script 标签的引用顺序
    })
  ]
});

module.exports = webpackConfig;
复制代码

4.util.js

'use strict';

//为了让打包以后的文件都在dist/static目录下
const path = require('path');

exports.assetsPath = function (_path) {
  const assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? 'static'
    : 'static';

  return path.posix.join(assetsSubDirectory, _path)
};
复制代码

5.webpack.config.js

module.exports = function (env, argv) {
  return argv.mode === 'production' ? 
  require('./configs/webpack.prod.conf') : 
  require('./configs/webpack.dev.conf');
};
复制代码

package.json文件

{
  "name": "promni-xmc-web",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --mode development",
    "build": "webpack --mode production"
  },
  "repository": {
    "type": "git",
    "url": "https://code.promni.cn/lihaofeng/promni-xmc-web.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.6.4",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^3.2.0",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.8.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "path": "^0.12.7",
    "postcss-loader": "^3.0.0",
    "pug-plain-loader": "^1.0.0",
    "raw-loader": "^3.1.0",
    "style-loader": "^1.0.0",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^2.2.0",
    "vue-loader": "^15.7.1",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.41.0",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2",
    "webpack-merge": "^4.2.2"
  },
  "dependencies": {
    "pug": "^2.0.4",
    "vue": "^2.6.10",
    "vue-router": "^3.1.3"
  }
}
复制代码

index.html文件

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>promni-xmc-web</title>
    <meta http-equiv=X-UA-Compatible content="chrome=1">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>	
复制代码

.babelrc文件

{"presets": ["env"]}	
复制代码

main.js入口文件

import Vue from 'vue'
import router from './router'
import App from './App'

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  render: h => h(App)
});
复制代码

App.vue文件

<template lang="pug">
    #app
        router-view
</template>

<script>
  export default {
    name: 'App'
  }
</script>
复制代码

router里面的index.js路由文件

import Vue from 'vue'
import Router from 'vue-router'

const test = r => require.ensure([], () => r(require('@components/test')));
Vue.use(Router);
const vueRouter = new Router({
  routes: [
    {
      path: '/',
      name: 'test',
      component: test
    }
  ]
});

export default vueRouter;
复制代码

test.vue文件

<template lang="pug">
    div
        p 我是首页
</template>
<style>
    p{
        color: red;
        background: url("../assets/img/logo.png") no-repeat;
    }
</style>	
复制代码

总结

到这里,最小可用的脚手架全部的文件源码已经完成,接下来就能够在compontents里面使用vue愉快的写咱们的业务代码了。使用方式:先用npm i添加package.json里面的依赖;开发环境使用npm run dev命令;生产环境使用npm run build命令打包。vue

相关文章
相关标签/搜索