纯webpack4构架+vue3.0 不采用vue-cli来生成
package.json 配置
{
  "name": "yuyue",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "node ./webpack/server.js",
    "build": "node ./webpack/build.js",
    "dll": "webpack --progress --config webpack/webpack.dll.js ---"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/preset-env": "^7.6.3",
    "@babel/preset-react": "^7.6.3",
    "add-asset-html-webpack-plugin": "^3.1.3",
    "amfe-flexible": "^2.2.1",
    "assets-webpack-plugin": "^3.9.10",
    "autoprefixer": "^9.6.5",
    "axios": "^0.19.0",
    "babel-loader": "^8.0.6",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "chalk": "^2.4.2",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.0.4",
    "css-hot-loader": "^1.4.4",
    "css-loader": "^3.2.0",
    "cssnano": "^4.1.10",
    "element-ui": "^2.12.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^4.2.0",
    "friendly-errors-webpack-plugin": "^1.7.0",
    "fs-extra": "^8.1.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "inobounce": "^0.2.0",
    "inquirer": "^7.0.0",
    "less": "^3.10.3",
    "less-loader": "^5.0.0",
    "lodash": "^4.17.15",
    "mini-css-extract-plugin": "^0.8.0",
    "mint-ui": "^2.2.13",
    "nodemon-webpack-plugin": "^4.1.1",
    "number-precision": "^1.3.1",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "ora": "^4.0.2",
    "postcss-loader": "^3.0.0",
    "progress-bar-webpack-plugin": "^1.12.1",
    "qs": "^6.9.0",
    "sass-resources-loader": "^2.0.1",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^2.2.0",
    "vue": "^2.6.10",
    "vue-awesome-swiper": "^3.1.3",
    "vue-loader": "^15.7.1",
    "vue-print-nb": "^1.4.0",
    "vue-qriously": "^1.1.1",
    "vue-seamless-scroll": "^1.1.17",
    "vue-template-compiler": "^2.6.10",
    "vuebar": "0.0.20",
    "vuex": "^3.1.1",
    "walk": "^2.3.14",
    "wangeditor": "^3.1.1",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2",
    "webpack-merge": "^4.2.2",
    "webpack-parallel-uglify-plugin": "^1.1.2"
  },
  "dependencies": {
    "core-js": "^3.3.3",
    "vue-router": "^3.1.3"
  }
}
{
  "name": "yuyue",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "node ./webpack/server.js",
    "build": "node ./webpack/build.js",
    "dll": "webpack --progress --config webpack/webpack.dll.js ---"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/preset-env": "^7.6.3",
    "@babel/preset-react": "^7.6.3",
    "add-asset-html-webpack-plugin": "^3.1.3",
    "amfe-flexible": "^2.2.1",
    "assets-webpack-plugin": "^3.9.10",
    "autoprefixer": "^9.6.5",
    "axios": "^0.19.0",
    "babel-loader": "^8.0.6",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "chalk": "^2.4.2",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.0.4",
    "css-hot-loader": "^1.4.4",
    "css-loader": "^3.2.0",
    "cssnano": "^4.1.10",
    "element-ui": "^2.12.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^4.2.0",
    "friendly-errors-webpack-plugin": "^1.7.0",
    "fs-extra": "^8.1.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "inobounce": "^0.2.0",
    "inquirer": "^7.0.0",
    "less": "^3.10.3",
    "less-loader": "^5.0.0",
    "lodash": "^4.17.15",
    "mini-css-extract-plugin": "^0.8.0",
    "mint-ui": "^2.2.13",
    "nodemon-webpack-plugin": "^4.1.1",
    "number-precision": "^1.3.1",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "ora": "^4.0.2",
    "postcss-loader": "^3.0.0",
    "progress-bar-webpack-plugin": "^1.12.1",
    "qs": "^6.9.0",
    "sass-resources-loader": "^2.0.1",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^2.2.0",
    "vue": "^2.6.10",
    "vue-awesome-swiper": "^3.1.3",
    "vue-loader": "^15.7.1",
    "vue-print-nb": "^1.4.0",
    "vue-qriously": "^1.1.1",
    "vue-seamless-scroll": "^1.1.17",
    "vue-template-compiler": "^2.6.10",
    "vuebar": "0.0.20",
    "vuex": "^3.1.1",
    "walk": "^2.3.14",
    "wangeditor": "^3.1.1",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2",
    "webpack-merge": "^4.2.2",
    "webpack-parallel-uglify-plugin": "^1.1.2"
  },
  "dependencies": {
    "core-js": "^3.3.3",
    "vue-router": "^3.1.3"
  }
}
1基础配置
const path = require(‘path‘);
const fs = require(‘fs-extra‘);
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin‘);
// 取本机IP地址
const getIPAdress = () => {
  var interfaces = require(‘os‘).networkInterfaces();
  for (var devName in interfaces) {
    var iface = interfaces[devName];
    for (var i = 0; i < iface.length; i++) {
      var alias = iface[i];
      if (alias.family === ‘IPv4‘ && alias.address !== ‘127.0.0.1‘ && !alias.internal) {
        return alias.address;
      }
    }
  }
}
//文件是否存在
const isFile = v => {
  return fs.pathExistsSync(v);
}
const [TARGET, clientItem] = [process.env.npm_lifecycle_event, process.argv[2]];
const vueLoader = {
  dev: "vue-style-loader",
  build: MiniCssExtractPlugin.loader,
  dll: MiniCssExtractPlugin.loader,
};
module.exports = {
  root: path.resolve(__dirname, ‘../‘),
  entry: path.resolve(__dirname, ‘../src/index.js‘),
  publicPath: ‘‘,
  outPath: path.resolve(__dirname, ‘../dist‘),
  devServer: getIPAdress() || ‘localhost‘,
  port: ‘6001‘,
  isFile: isFile,
  getIPAdress: getIPAdress,
  vueLoader: vueLoader[TARGET],
  host:‘0.0.0.0‘
}
const path = require(‘path‘);
const fs = require(‘fs-extra‘);
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin‘);
// 取本机IP地址
const getIPAdress = () => {
  var interfaces = require(‘os‘).networkInterfaces();
  for (var devName in interfaces) {
    var iface = interfaces[devName];
    for (var i = 0; i < iface.length; i++) {
      var alias = iface[i];
      if (alias.family === ‘IPv4‘ && alias.address !== ‘127.0.0.1‘ && !alias.internal) {
        return alias.address;
      }
    }
  }
}
//文件是否存在
const isFile = v => {
  return fs.pathExistsSync(v);
}
const [TARGET, clientItem] = [process.env.npm_lifecycle_event, process.argv[2]];
const vueLoader = {
  dev: "vue-style-loader",
  build: MiniCssExtractPlugin.loader,
  dll: MiniCssExtractPlugin.loader,
};
module.exports = {
  root: path.resolve(__dirname, ‘../‘),
  entry: path.resolve(__dirname, ‘../src/index.js‘),
  publicPath: ‘‘,
  outPath: path.resolve(__dirname, ‘../dist‘),
  devServer: getIPAdress() || ‘localhost‘,
  port: ‘6001‘,
  isFile: isFile,
  getIPAdress: getIPAdress,
  vueLoader: vueLoader[TARGET],
  host:‘0.0.0.0‘
}
2、webpack 基本配置 webpack.base.js
let HtmlWebpackPlugin = require(‘html-webpack-plugin‘);
let config = require(‘./webpack.config.js‘);
const path = require(‘path‘);
const VueLoaderPlugin = require(‘vue-loader/lib/plugin‘);
const webpack = require(‘webpack‘);
const AddAssetHtmlPlugin = require(‘add-asset-html-webpack-plugin‘);
module.exports = {
  entry: config.entry,
  output: {
    filename: ‘bundle.js‘,
    path: config.outPath,
    publicPath: ‘./‘,
    chunkFilename: ‘[name].vue.js‘
  },
  resolve: {
    alias: {
      ‘lib‘: path.join(config.root, ‘lib/‘),
      ‘@css‘: path.join(config.root, ‘src/css‘),
      ‘vue$‘: ‘vue/dist/vue.esm.js‘,
    },
    modules: [‘node_modules‘, ‘*‘],
    extensions: [‘.ts‘, ‘.tsx‘, ‘.js‘, ‘.jsx‘, ‘.json‘, ‘.vue‘]
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        config.vueLoader, {
          loader: "css-loader"
        }, {
          loader: "postcss-loader",
          options: { plugins: [require("autoprefixer")] }
        }
      ]
    },
    {
      test: /\.less$/,
      use: [
        config.vueLoader, {
          loader: "css-loader"
        }, {
          loader: "postcss-loader",
          options: { plugins: [require("autoprefixer")] }
        }, {
          loader: "less-loader"
        }, {
          loader: ‘sass-resources-loader‘,
          options: {
            resources: path.join(config.root, ‘src/css/base.less‘),
          }
        }
      ]
    },
    {
      test: /\.vue$/,
      loader: ‘vue-loader‘,
      options: {
        transformAssetUrls: {
          video: [‘src‘, ‘poster‘],
          source: ‘src‘,
          img: ‘src‘,
          image: ‘xlink:href‘
        },
        compilerOptions: {
          preserveWhitespace: false
        }
      }
    },
    {
      test: /\.js$/,
      use: {
        loader: ‘babel-loader‘,
        options: {
          plugins: [‘@babel/plugin-proposal-class-properties‘, ‘syntax-dynamic-import‘]
        }
      },
      exclude: /node_modules/,
      // include: [process.cwd(), ‘./src‘]
    },
    {
      test: /\.(gif|png|jpe?g|svg|ico)$/i,
      use: [{
        loader: ‘url-loader‘
      },
      ]
    },
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,   // 处理字体
      use: {
        loader: ‘file-loader‘
      }
    }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require(‘./vendor/vue-manifest.json‘)
    }),
    new HtmlWebpackPlugin({
      filename: `index.html`,
      template: config.root + ‘/src/index.html‘,
      title: ‘wyulang‘,
      prod: true,
      hash: true,
      minify: {
        removeAttributeQuotes: true,
        collapseWhitespace: true,
        html5: true,
        minifyCSS: true,
        removeComments: true,
        removeEmptyAttributes: true
      }
    }),
    new AddAssetHtmlPlugin({
      filepath: path.resolve(__dirname, ‘./vendor/vue.library.js‘),
    })
  ]
}
3、webpack 开发环境配置 webpack.dev.js
const ProgressBarPlugin = require(‘progress-bar-webpack-plugin‘);
const FriendlyErrorsPlugin = require(‘friendly-errors-webpack-plugin‘);
const webpackbase = require(‘./webpack.base.js‘);
const webpack = require(‘webpack‘);
const merge = require(‘webpack-merge‘);
let config = require(‘./webpack.config.js‘);
const chalk = require(‘chalk‘);
const NodemonPlugin = require(‘nodemon-webpack-plugin‘);
let webpackDevConfig = {
  devtool: ‘source-map‘,
  mode: ‘development‘,
  devServer: {
    open: false,
    contentBase: config.outPath,
    publicPath: "/",
    hot: true,
    noInfo: true,
    port: config.port,
    host: config.host,
    historyApiFallback: {
      index: ‘/index.html‘ //与output的publicPath有关(HTMLplugin生成的html默认为index.html)
    }
  },
  plugins: [
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new FriendlyErrorsPlugin({
      compilationSuccessInfo: {
        messages: [chalk.cyan.bold(‘Your application is running here: ‘) + chalk.greenBright.bold(`http://${config.devServer}:${config.port}/`)]
      }
    }),
    new ProgressBarPlugin(
      {
        format: chalk.blueBright(‘  build :bar :percent (:elapsed seconds) ‘),
        clear: true,
        summary: false,
        customSummary: res => {
          process.stderr.write(chalk.blueBright(‘   ‘))
        }
      }
    ),
    // new NodemonPlugin()
  ]
}
module.exports = merge(webpackbase, webpackDevConfig)
4、webpack 生产打包环境配置 webpack.prod.js
const merge = require(‘webpack-merge‘);
const webpackbase = require(‘./webpack.base.js‘);
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin‘);
const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin‘);
const OptimizeCssAssetsPlugin = require(‘optimize-css-assets-webpack-plugin‘);
const chalk = require(‘chalk‘);
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin‘);
const config = require(‘./webpack.config.js‘);
const HtmlWebpackPlugin = require(‘html-webpack-plugin‘);
const ParallelUglifyPlugin = require(‘webpack-parallel-uglify-plugin‘);
const _version = new Date().getTime();
const webpackProdConfig = {
  devtool: ‘inline-cheap-source-map‘,
  mode: ‘production‘,
  optimization: {
    noEmitOnErrors: true,
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: false // set to true if you want JS source maps
      }),
      new OptimizeCssAssetsPlugin({
        cssProcessor: require(‘cssnano‘)
      })
    ],
    splitChunks: {
      chunks: ‘all‘
    }
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: `[name].${_version}.css`,
      chunkFilename: `[name].${_version}.css`,
    }),
    new ProgressBarPlugin(
      {
        format: chalk.blueBright(‘ build :bar :percent (:elapsed seconds) ‘),
        clear: false,
        summary: false,
        customSummary: res => {
          process.stderr.write(chalk.blueBright.bold(` build end use time ${res} \n`))
        }
      }
    ),
  ]
}
module.exports = merge(webpackbase, webpackProdConfig)
5、webpack 公共库环境配置 webpack.dll.js
‘use strict‘
const path = require(‘path‘)
const webpack = require(‘webpack‘)
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin‘)
const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin‘);
let config = require(‘./webpack.config.js‘);
let webpackDll = {
  mode: ‘production‘,
  entry: {
    vue: [
      ‘vue/dist/vue.esm.js‘,
      ‘vuex‘,
      ‘axios‘,
      ‘vue-router‘
    ]
  },
  output: {
    path: path.join(__dirname, ‘../webpack/vendor/‘), // 生成的文件存放路径
    filename: ‘[name].library.js‘, // 生成的文件名字(默认为dll.vendor.[hash].js)
    library: ‘[name]_library‘ // 生成文件的映射关系,与下面DllPlugin中配置对应
  },
  optimization: {
    noEmitOnErrors: true,
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: false // set to true if you want JS source maps
      })
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new webpack.DllPlugin({
      path: path.join(__dirname, ‘../webpack/vendor/[name]-manifest.json‘),
      name: ‘[name]_library‘, // 与上面output中配置对应
      context: __dirname // 上下文环境路径(必填,为了与DllReferencePlugin存在与同一上下文中)
    })
  ]
}
module.exports = webpackDll;
6、server启动配置 server.js
const webpack = require("webpack");
const webpackConfig = require("./webpack.dev.js");
let WebpackDevServer = require(‘webpack-dev-server‘);
let config = require(‘./webpack.config.js‘);
const compiler = webpack(webpackConfig);
const devServerOptions = Object.assign({}, webpackConfig.devServer);
const server = new WebpackDevServer(compiler, devServerOptions);
server.listen(config.port, config.host, res => {});
7、打包配置 build.js
const webpack = require(‘webpack‘) // 加载 webpack
const webpackConfig = require("./webpack.prod.js");
const chalk = require(‘chalk‘);
const ora = require(‘ora‘);
process.stderr.write(chalk.blueBright.bold(` build start ..... \n\n`));
webpack(webpackConfig, (err, state) => {});
第一次启动 之前先运行一次 npm run dll
启动命令
npm run dev
打包命令
npm run build
完整项目gitHub地址 https://github.com/wyulang/vue4
