One webpack package for two projects

Preface: Intricate file dependencies, inefficient static resource requests, unfriendly modular support, and low browser compatibility with advanced JS? Then it's time to learn about webpack

First, a simple understanding of webpack

(1) Concept

webpack is a static module bundler builder  for JavaScript applications . When processing an application, webpack recursively builds a dependency graph containing every module the application needs, and then bundles all those modules into one or more  bundles . Webpack provides friendly modular support, as well as code compression obfuscation, advanced js compatibility, and performance optimization.

(2) Core

1. Entry: Specify which file to start with webpack packaging and compilation

The entry point tells webpack which module to use as the start of building its internal dependency graph . After entering the entry point, webpack will find out which modules and libraries are (directly and indirectly) dependent on the entry point.

webpack.config.js:

module.exports = {
 entry: {
    main: './src' //打包入口,来指定一个入口起点(或多个入口起点,默认值为 ./src)
  },
 entry: './src', //这个是上面的简写方式,是等价的
 entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
 },//对象法指定多个入口,如果你想要多个依赖一起注入到一个模块,向 entry 属性传入「文件路径(file path)数组」。
 entry: () => new Promise((resolve) => resolve(['./demo', './demo2'])),//动态入口,当结合 output.library 选项时:如果传入数组,则只导出最后一项
};

2. Export (output): Specify the path and file name after webpack is packaged and compiled

The output  property tells webpack where to output the  bundles it creates , and how to name those files. Basically, the entire application structure, will be compiled into the folder you specify in the output path.

webpack.config.js:

const path = require('path');

module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist'),//打包文件夹名,默认值为 ./dist
    filename: '[name].js'//入口文件名
  }
};

3.loader (loader): the language that webpack cannot recognize is translated by the loader

Loaders are used to convert certain types of modules. Webpack itself only understands JavaScript. Loaders   can convert all types of files into valid modules that webpack can handle . The loader can   import any type of module (eg  ), which is a unique feature of webpack and may not be supported by other packaging tools.import.css

webpack.config.js:

const path = require('path');

const config = {
  module: {
    rules: [//在 webpack 配置中定义 loader 时,要定义在 module.rules 中,里面包含两个"必须属性":test 和 use
      { 
        test: /\.txt$/, //test 定义需要使用相应 loader 进行转换的某类文件
        use: 'raw-loader' //use 定义使用哪个 loader 进行转换
      } 
    ]
  }
};

module.exports = config;

4. Plugins (plugins): The functions that webpack cannot complete are completed through plug-ins

The plugin interface is extremely powerful and can be used to handle a wide variety of tasks. By require() using the plugin and then adding it to the  plugins array. Most plugins can be customized via options.

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件

const config = {
  plugins: [
    //在一个配置文件中因为不同目的而多次使用同一个插件,需要通过使用 new 操作符来创建它的一个实例
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

5. Mode: The mode is used to determine whether it is a development environment or a production environment in order to load different configurations

module.exports = {
  mode: 'production'//通过选择 development(开发) 或 production(生产),启用相应模式下的 webpack 内置的优化
};

6. Configuration

webpack needs to pass in a configuration object, which is parsed according to the properties defined by the object, so very few webpack configurations look exactly the same. The configuration file of webpack is a JavaScript file that exports an object. There are two ways to use webpack (terminal, Node.js).

 The webpack configuration is a standard Node.js CommonJS module, you can:

  • by  require(...) importing other files
  • By  require(...) using npm's utility functions
  • Use JavaScript control flow expressions, such as  ?: operators
  • Use constants or variables for common values
  • Write and execute functions to generate partial configuration

The following practices should be avoided :

  • Access command line interface (CLI) parameters when using webpack command line interface (CLI) (should write your own command line interface (CLI), or use  )--env
  • Export indeterminate values ​​(calling webpack twice should produce the same output file)
  • Write very long configuration, which should be split into multiple files

Second, build one

(1) Prerequisites

 The webpack configuration is a standard Node.js CommonJS module. Before installing webpack, please make sure that the latest version of  Node.js is installed  . Using the old version may encounter various problems (may be lack of webpack function or lack of related packages).

(2) Preparations

1. Install webpack

For most projects, a local installation is recommended. This makes it easier to upgrade projects individually when a breaking change of a dependency is introduced. Installing webpack globally is not recommended. This will lock webpack in your project to the specified version, and may cause build failures in projects using different webpack versions.

①本地安装
npm install --save-dev webpack //安装最新版本
npm install --save-dev webpack@<version> //安装特定版本

②全局安装 
npm install --global webpack

2. Install CLI

If you're using webpack 4+, you'll also need to install the CLI, the tool used to run webpack from the command line.

npm install --save-dev webpack-cli //webpack-cli用于在命令行中运行 webpack

(3) Good operation

In an existing project:

npm init -y  //初始化webpack  这里会自动生成一个package.json
npm i -D webpack webpack-cli //安装webpack及其脚手架

One project package two projects demo1 and demo2 (applicable to the functional requirements of the two projects are very similar, there are differences in common places):

{
  "name": "webpackstudy",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "demo1-start": "webpack-dev-server --progress --color",
    "demo2-start": "webpack-dev-server --progress --color",
    "demo1-mock": "webpack-dev-server --progress --color",
    "demo2-mock": "webpack-dev-server --progress --color",
    "demo1-te": "webpack --progress --color",
    "demo2-te": "webpack --progress --color"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.19.0",
    "vue": "^2.6.10",
    "vue-pull-to": "^0.1.8",
    "vue-router": "^3.1.2",
    "vuex": "^3.1.1"
  },
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "autoprefixer": "^9.6.1",
    "babel-loader": "^8.0.6",
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^3.2.0",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "html-withimg-loader": "^0.1.16",
    "jsonc": "^2.0.0",
    "less": "^3.10.2",
    "less-loader": "^5.0.0",
    "mini-css-extract-plugin": "^0.8.0",
    "mocker-api": "^1.8.1",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "postcss-loader": "^3.0.0",
    "style-loader": "^1.0.0",
    "terser-webpack-plugin": "^1.4.1",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^2.1.0",
    "vue-loader": "^15.7.1",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.39.2",
    "webpack-cli": "^3.3.7",
    "webpack-dev-server": "^3.8.0"
  }
}
const path = require('path');
const webpack = require('webpack');
// script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题; 自动创建html入口文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 用terser-webpack-plugin替换掉uglifyjs-webpack-plugin解决uglifyjs不支持es6语法问题
const TerserJSPlugin = require('terser-webpack-plugin');
// 此模块至少需要Node v6.9.0和webpack v4.0.0  混淆代码
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
// 这个插件将CSS提取到单独的文件中 支持按需加载CSS和SourceMaps 建立在webpack v4上
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 用于优化、压缩CSS资源
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// 打包时将之前打包的目录里的文件先清除干净,再生成新的
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
//mock数据
const apiMocker = require('mocker-api');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
//获取 npm run 后面的命令
const lifecycle = process.env.npm_lifecycle_event;
//npm run 的文件名
const project = lifecycle.split('-')[0];
//npm run 的环境名
const proMode = lifecycle.split('-')[1] === 'te';
const envMode = lifecycle.split('-')[1];
const webpackConfig = {
    mode: proMode ? 'production' : 'development',
    //打包入口为每个项目的main.js
    entry: path.resolve(__dirname, `${project}/main.js`),
    output: {
        //打包后的文件目录为各自项目名+Dist
        path: path.resolve(__dirname, `${project}Dist`),
        //打包后源代码映射
        // devtool: proMode ?'cheap-module-eval-source-map':'hidden-source-map',
        // devtool: "inline-source-map",
        //打包后的出口js目录
        filename: 'js/[name].[hash].js',
        //分块打包的js目录
        chunkFilename: proMode ? 'js/[name].[contenthash].bundle.js' : 'js/[name].bundle.js',
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                use: {
                    loader: 'vue-loader'
                }
            },
            {
                test: /\.(le|c)ss$/i,
                use: [
                    proMode ? MiniCssExtractPlugin.loader :
                        'vue-style-loader',
                    'css-loader',
                    'postcss-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.html$/i,
                use: [
                    'html-withimg-loader'
                ]
            },
            {
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 4096,
                            name: 'img/[name].[contenthash].[ext]'
                        },
                    },
                ],
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }
        ]
    },
    //webpack-dev-server 配置npm run 时启动本地服务
    devServer: {
        contentBase: `./${project}Dist`,
        inline: true //实时刷新
    },
    //优化
    optimization: {
        // 分块
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all'
                },
            }
        }
    },
    plugins: [
        new CleanWebpackPlugin(),
        //定义插件—— 在项目中可以读取到
        new webpack.DefinePlugin({
            'baseUrl':proMode ? 'https:www.baidu.com':JSON.stringify('localhost')
        }),
        new HtmlWebpackPlugin({
            title:'webpack练习',
            filename: 'index.html',
            template: `${project}/index.html`,
            // 对 html 文件进行压缩
            minify: {
                //是否对大小写敏感,默认false
                caseSensitive: false,

                //是否简写boolean格式的属性如:disabled="disabled" 简写为disabled  默认false
                collapseBooleanAttributes: true,
                //是否去除空格,默认false
                collapseWhitespace: true,

                //是否压缩html里的css(使用clean-css进行的压缩) 默认值false;
                minifyCSS: true,

                //是否压缩html里的js(使用uglify-js进行的压缩)
                minifyJS: true,
                //是否移除注释 默认false
                removeComments: true,
                //Prevents the escaping of the values of attributes
                preventAttributesEscaping: true,

                //是否移除属性的引号 默认false
                removeAttributeQuotes: true,

                //从脚本和样式删除的注释 默认false
                removeCommentsFromCDATA: true,

                //是否删除空属性,默认false
                removeEmptyAttributes: false,

                //  若开启此项,生成的html中没有 body 和 head,html也未闭合
                removeOptionalTags: false,

                //删除多余的属性
                removeRedundantAttributes: true,

                //删除script的类型属性,在h5下面script的type默认值:text/javascript 默认值false
                removeScriptTypeAttributes: true,

                //删除style的类型属性, type="text/css" 同上
                removeStyleLinkTypeAttributes: true,

                //使用短的文档类型,默认false
                useShortDoctype: false,
            }
        }),
        new VueLoaderPlugin()
    ],
    //目录映射
    resolve: {
        alias: {
            '@assets': path.resolve(__dirname, `${project}/assets`),
            '@mixins': path.resolve(__dirname, `${project}/mixins`),
            '@tools': path.resolve(__dirname, `${project}/tools`),
            '@components': path.resolve(__dirname, `${project}/components`),
        }
    }
};
if (proMode) {
    webpackConfig.optimization.minimizer = [
        //混淆语法
        new UglifyJsPlugin({
            chunkFilter: (chunk) => {
                if (chunk.name === 'vendor') {
                    return false;
                }
                return true;
            },
            //去掉控制台日志
            uglifyOptions: {
                compress: {
                    drop_console: true
                }
            }
        }),
        new OptimizeCssAssetsPlugin({})
    ];
    // webpackConfig.optimization.minimizer = [new TerserJSPlugin({}),
    //     new OptimizeCssAssetsPlugin({}),];
    webpackConfig.plugins.push(
        new MiniCssExtractPlugin({
            filename: proMode ? '[name].css' : '[name].[hash].css',
            chunkFilename: proMode ? '[id].css' : '[id].[hash].css',
        })
    )
} else {
    // 热更新模块
    webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
    webpackConfig.devtool = 'inline-source-map';
    if (envMode == 'mock') {
        //mock环境,启用mock代理服务
        webpackConfig.devServer.before = (app) => {
            apiMocker(app, path.resolve(`${project}/mock/api.js`));
        };
        //非mock匹配项走测试环境
        webpackConfig.devServer.proxy = process.baseUrl;
    }
}
module.exports = webpackConfig;

 

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324142832&siteId=291194637