preface

Recently, I reviewed the knowledge of Webpack, and felt that it is not good to learn Webpack just by watching it without practicing it, so I came up with the idea of manually building a Vue3+Ts running environment. Without further ado, just start building.

Create a folder and go to the directory

Generate package.json file

If your directory name is valid, just add -y. This means yes for all options.

npm init
Copy the code

Install Webpack, webPack – CLI

Here webpack and Webpack-CLI are required in the development environment, but not in the build environment. So plus minus D theta

npm install webpack webpack-cli -D
Copy the code

Create the script in package.json

We can package directly from the command line via NPX webpack, but we can also create a build script in the package.json file to perform the package via NPM run build.

Create the WebPack configuration file

By default, webpack can be configured by creating a webpack.config.js file in the root directory. However, there may be more commands to be configured later. So here we split the webPack configuration file. Create a webpack_config folder in the root directory. Within this folder, create three files: Webpack.common.js (for general configuration), webpack.dev.js (for development environment configuration), webpack.prod.js (for production environment configuration).

Because by default, webpack reads the configuration of the webpack.config.js file, we are not modifying the file for configuration, so we need to specify the directory of the configuration file. We can set it directly in the script command in package.json file.

Configure the webpack.common.js file as follows

const path = require('path')

module.exports = {
  entry: './src/main.js'.// Set the packaged entry file, there is no need to.. /. Because this is relative to context, and the path to context is the root directory.
  output: {
    path: path.resolve(__dirname, '.. /bundle'), // There is a need for... /, because this is not relative to context.
    publicPath: '/'To configure the prefix to import resources into index.html after packagingfilename: 'js/[name].[chunkhash:6].bundle.js'.clean: true   // Delete the packed files before packing them.}}Copy the code

Handle CSS, less files

Install csS-loader to process CSS files. Install style-loader (to insert styles into HTML using style tags).

Install less-loader to process less files.

Install postCSs-loader, postCSs-preset -env (this is a plugin) for adding browser prefixes to CSS files.

npm install css-loader style-loader less-loader postcss-loader postcss-preset-env -D
Copy the code

configure

/ / on the webpack.com mon. Js
module.exports = {
    ...
    module: {
        rules: [{test: /\.css$/.// Matches the CSS file
            use: [
              "style-loader",
              {
                loader: "css-loader".options: {
                  importLoaders: 1.// there are several loaders before csS-loader}, {},loader: "postcss-loader".options: {   
                  postcssOptions: {    // The configuration of postCSS can also be extracted into a separate file, which is not extracted here.
                    plugins: ['postcss-preset-env'],}},},],}, {test: /\.less$/,
            use: [
              'style-loader',
              {
                loader: 'css-loader'.options: {
                  importLoaders: 2}}, {loader: 'postcss-loader'.options: {
                  postcssOptions: {
                    plugins: ['postcss-preset-env']}}},'less-loader']]}},Copy the code

Handle images and font resources

In Webpack5, you can use asset Module Type to handle these resources without installing file-loader or url-loader.

configure

// webpack.common.js
module.exports = {
    ...
    module: {
        rules: [{test: /\.(jpe? g|svg|png)$/.// Matching resources
                type: 'asset'.// asset is a combination of file-loader and url-loader
                generator: {
                  filename: 'img/[name].[hash:6][ext]' // The generated file name
                },
                parser: {
                  dataUrlCondition: {
                    maxSize: 10 * 1024  // If the generated image is less than 10KB, no image will be generated and base64 will be converted}}}, {test: /\.(tff|woff|ttf)$/,
                type: "asset".generator: {
                  filename: "fonts/[name].[hash:6][ext]",},parser: {
                  dataUrlCondition: {
                    maxSize: 8 * 1024,},},},]}}Copy the code

Generating HTML files

So far, our packaged files have no HTML files. If we want to generate HTML files after packaging, we can use the HTml-webpack-plugin to help us generate HTML files. The generated HTML will automatically help us with the file import.

HTML – webpack – the plugin installation.

npm install html-webpack-plugin -D
Copy the code

When using the plugin, we can either specify an HTML template for it or have it automatically generate HTML files for us

configure

// webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')  // Import the plug-in

module.exports = {
    ...
    plugins: [
        new HtmlWebpackPlugin() // If you need to further configure the plug-in, you can do your own research]}Copy the code

Creating a service

During vUE development, we execute NPM Run Serve to create a local service. In Webpack, if you want to create a local service, you need to install webpack-dev-server

npm install webpack-dev-server -D
Copy the code

Create a script in package.json file

Then run NPM run serve to start a local service.

With the local service created, we can do some configuration for the local service. These configurations are used during development and not during packaging, so the previous configurations are separated here.

Separate configuration files

First, when executing the script, we can pass in a parameter so that we can determine whether we currently want to use a development configuration or a production configuration.

When our configuration file exports a function, WebPack passes us the parameters we pass as parameters to the function, and we can use this parameter to decide which configuration to use.

In addition to getting the configuration mode, we also need to merge the configuration commands. You can use the Webpack-Merge plug-in to help you merge configurations.

npm install webpack-merge -D
Copy the code
// webpack.common.js
const { merge } = require('webpack-merge') // Merge function

const commonConfig = {} // This object holds the previous configuration

module.exports = (env) = > {
  // Determine the current mode
  const mode = env.production ? 'production' : 'development'
  let config = null
  // Import different configurations according to different modes
  if (mode === 'production') {
    config = require('./webpack.prod')}else {
    config = require('./webpack.dev')}// Returns the merged configuration file
  return merge(commonConfig, config)
}

Copy the code

Configuration devServer

// webpack.dev.js
module.exports = {
    mode: 'development'.devtool: 'cheap-module-source-map'.// Set source-map file for easy debugging of development code
    devServer: {
        hot: true.// Enable module hot replacement, which is enabled by default
        historyApiFallback: {  // The route history mode refresh page is lost
            rewrites: [{from: / \. * /.// Match all paths
                    to: '/index.html'  // Map to the index.html file}]}}}Copy the code

Working with JS files

When packaging, in order to do browser adaptation, we need to install ES6+ JS into ES5 code. At this point we can use Babel to help us change.

Install babel-loader @babel/ core@babel /preset-env.

npm install @babel/core @babel/preset-env @babel-loader -D
Copy the code

configure

Because of the adaptation of JS code, it only needs to be converted at packaging time. There is no need to transform the code during development, so just configure it in the PROd file.

module.exports = {
  mode: 'production'.module: {
    rules: [{test: /\.js$/,
        exclude: /node_modules/.// Do not process js files under node_modules, so it does not consume packaging time
        use: {
          loader: 'babel-loader'.options: {
            presets: ['@babel/preset-env'}}}]}}Copy the code

Processing TS files

Ts files can be processed using babel-loader and @babel/preset-typescript, as well as TS-loader. Here I use the development of the use of TS-loader so that the following TS error detection. Package using babel-loader, so you can convert js to do compatibility processing.

To use ts-loader, you must have the tsconfig.json file. If not, you can use TSC –init on the terminal. If an error is reported, install typescript globally.

npm install @babel/preset-typescript ts-loader typescript -D
Copy the code

configure

Configuration in the development environment

// webpack.dev.js
module.exports = {
    ...
    module: {
        rules: [{test: /\.ts$/,
            exclude: /\.ts$/,
            use: {
              loader: 'ts-loader'.options: {
                  appendTsSuffixTo: [/\.vue$/].// Handle using ts in vue files
                  transpileOnly: true.// Turn off type detection to reduce compile time.}}}]}}Copy the code

In the above configuration, we turned off type checking to reduce compilation time, and we could have handed over the responsibility of type checking to another plug-in that would have started another thread to help us with type checking.

Install the fork-ts-checker-webpack-plugin

npm install fork-ts-checker-webpack-plugin -D
Copy the code

Add the use of this plug-in to the configuration above.

// webpack.dev.js
const ForkTsCheckerWebapckPlugin = require('fork-ts-checker-webpack-plugin')// Import the plug-in

module.exports = {
    ...
    module: {
        rules: [{test: /\.ts$/,
            exclude: /node_modules/,
            use: {
              loader: 'ts-loader'.options: {
                  appendTsSuffixTo: [/\.vue$/].// Handle using ts in vue files
                  transpileOnly: true.// Turn off type detection to reduce compile time.}}}]}plugins: [
       new ForkTsCheckerWebpackPlugin()
   ] 
  }
Copy the code

Configuration in the generation environment

// webpack.prod.js
module.exports = {
    ...
  module: {
    rules: [{test: /\.ts$/,
        use: {
          loader: 'babel-loader'.options: {
            presets: [
              '@babel/preset-env'['@babel/preset-typescript', {
                // This configuration is used to process ts files after.vue files have been parsed
                allExtensions: true}}}}}Copy the code

Processing. Vue files

To process.vue files, vue-Loader and @vue/ Compiler-sFC are required. Because you are currently working with vue3 files, and vue3 is not the default version, you need to install vue-loader@next. When vue3 becomes the default version, you can install it directly.

npm install @vue/compiler-sfc vue-loader@next -D**
Copy the code

This is because.vue files need to be processed in both development and build environments. So here we put the processing configuration for the.vue file in the webpack.common.js file.

configure

const { VueLoaderPlugin } = require('vue-loader')  / / import VueLoaderPlugin
module.exports = {
    ...
    module: {
        rules: [{test: /\.vue$/,
                exclude: /node_modules/,
                loader: 'vue-loader'}},plugins: [
        new VueLoaderPlugin()  // Use this plugin here]}Copy the code

Once packaged, runtime will find the following warning

This warning means that Vue strongly recommends that we define our own variables __VUE_OPTION_API_ and VUE_PROD_DEVTOOLS, which are used to decide whether to use optionsAPI and whether to enable the Devtools plugin. We can define it according to our own situation.

How to define global variables in Webpack can be done using the DefinePlugin built into WebPack.

// webpack.common.js
const { DefinePlugin } = require('webpack')

module.exports = { ... Plugins:new DefinePlugin({
            __VUE__OPTION_API__: false.__VUE_PROD__DEVTOOLS: true}})]Copy the code

Once you have defined the global variable, open it again and you will find no warning.

conclusion

With the basic configuration above, we are ready to run vue3 and TS projects. There are also some optimizations that need to be made to the project, which will be addressed later.