Build multi-page application based on vue2 and WebPack3Github.com/FedWithMori…
I. Project directory structure
One of the first things to do before any project starts construction is to determine the directory structure of our project, both the development directory and the production directory.
1. Develop a catalog
. ├ ─ ─ the README. Md ├ ─ ─ build │ ├ ─ ─ devtool. Js / / service configuration │ ├ ─ ─ entry. The js / / get all the entrance paths │ ├ ─ ─ the output. The js / / output │ ├ ─ ─ plugins. Js / / ├─ ├─ SRC ├─ assets ├─ ├─ download.json ├─ └ webpack.config.dev.js // Development environment ├─ webpack.config.js // production environment ├─ SRC ├─ assets // static directory │ ├─ less │ ├─ mixin. Less │ ├─ reset. Less │ ├── images // Images │ ├─ home │ ├─ home │ ├ ─ ─ index. PNG │ ├ ─ ─ the about the PNG │ ├ ─ ─ fonts / / font │ ├ ─ ─ aleem walji off ├ ─ ─ the components / / component │ ├ ─ ─ button. The vue ├ ─ ─ entry/js/entry │ ├ ─ ─ home │ ├ ─ ─ home. Js │ ├ ─ ─ index. The js │ ├ ─ ─ the about the js ├ ─ ─ page/page/module │ ├ ─ ─ home │ ├ ─ ─ home. Vue │ ├ ─ ─ index. The vue │ ├ ─ ─ about.vueCopy the code
2. Production catalog
. ├ ─ ─ dist ├ ─ ─ CSS ├ ─ ─ HTML ├ ─ ─ js ├ ─ ─ images ├ ─ ─ fonts ├ ─ ─ vendorCopy the code
Start building the project
Step 1: Create a new project directory
Enter the following command on the cli to create a directory: mkdir vue2-webpack3
Step 2: Initialize the project
2.1 Directly enter the command CD vue2-webpack3 in the CLI to enter the project 2.2, then enter the command NPM init, then input the relevant information and then enter yes to save the relevant project information 2.3 At this time, there is a package.json file in the project. This file contains some information about our project, which can be found in the package.json documentation
Step 3: Build the project structure
3.1 Create all directories based on the development directory structure
3.2 Then it’s webpack’s turn
As you all know, webPack configuration files are mainly composed of: Entry, output, module, plugins, devtool and so on several parts, in order to facilitate management (if all in one file, as the project of large too much can lead to the content of the configuration page), I alone to set up a file in addition to the module of several attribute
3.3 entry configuration
Since we are a multi-page application, we must have a lot of entry files. To facilitate access to all entry files, we can use Node fs file system to obtain the path of all entry files in the Entry directory, the code is as follows:
const fs = require('fs');
const path = require('path');
const directory = path.resolve(__dirname, '.. /src/entry');const entryList = {};
(getEntry = (dir) = > {
const entryArr = fs.readdirSync(dir);
let pathName,
filePath;
entryArr.forEach(function(filename) {
filePath = dir + '/' + filename;
if(fs.statSync(filePath).isDirectory()) {
getEntry(filePath);
} else {
pathName = filePath.split('entry/') [1].replace('.js'.' ');
entryList[pathName] = filePath;
}
})
})(directory)
module.exports = entryListCopy the code
Simple parsing of this code, the main use of fs.readdirSync and fs.statSync two methods. The fs.readdirSync method can retrieve all file paths from the path you provided, such as the dir I passed above (note that the fs.readdirSync parameter must be an absolute path; relative paths cannot be retrieved). Fs. readdirSync will return the path of all the files in the entry. Then we will use fs.statSync to determine whether the path corresponds to a file or a directory. If it is a directory, we will call it again until we get the path of the file.
3.4 Solve the problem of import file, then continue to configure output, the code is as follows:
const path = require('path');
module.exports = {
path: path.resolve(__dirname, '.. /dist'),
// publicPath: 'http://img.xxx.com',
filename: 'js/[name].js? ver=[hash:6]'
}Copy the code
Path outputs all js files to dist/js, filename outputs all JS files to dist/js, and [name] corresponds to the pathName in the import file. If necessary, you can also configure publicPath. For example, static is packaged separately on a server, so we need to treat static paths uniformly.
3.5 After configuring the inlet and outlet, continue to configure some Loaders from the inlet to the outlet. The code is as follows:
rules: [
{
test: /\.less$/.exclude: /node_modules/.use: ExtractTextPlugin.extract(['css-loader'.'less-loader'])}, {test: /\.vue$/.loader: 'vue-loader'.options: {
loaders: {
less: ExtractTextPlugin.extract({
use: ['css-loader'.'less-loader'].fallback: 'vue-style-loader'})}}}, {test: /\.js$/.exclude: /node_modules/.loader: 'babel-loader'
},
{
test: /\.(jpg|jpeg|png|gif)$/.loaders: 'url-loader'.options: {
limit: 10000}}, {test: /\.(woff|woff2|svg|eot|ttf)$/.use: 'file-loader'}]Copy the code
The loader configuration is simple, but there are a few issues to be aware of. 1) I want to be able to separate the styles of vue components from those of less into CSS files, so I need to use the extract-text-webpack-plugin, which will be used later. 2) I want to use the plugin to automatically complete the prefixes of CSS styles. So I introduced the PostCSs-loader converter and autoprefixer rules. For auto-complete configuration, I directly created postcss.config.js and did the following simple configuration:
module.exports = {
plugins: {
'autoprefixer': {}}}Copy the code
After this configuration, the project will read the contents of the configuration file by default when compiling LESS and perform subsequent processing based on the contents. 3) I also want to be able to use the ES6 syntax for development, so we need to rely on Babel for translation. There is also babel-loader in Webpack for this, so we need to install the plugin by executing the following command:
npm i babel-loader babel-core babel-preset-env babel-plugin-transform-runtime --save-dev
npm i babel-runtime --saveCopy the code
After installation, create a.babelrc file to configure Babel as follows:
{
presets: [['env',
{
'targets': {
'browsers': ['last 2 versions'.'ie >= 8']}}]],plugins: ['transform-runtime']}Copy the code
Presets are used to tell Babel which syntax version to use for translation. For example, babel-PRESET – ES2015 is common.
{
presets: ['es2015']}Copy the code
According to this configuration, Babel will translate all the syntaxes of es2015 to ES5, so some ES2016, ES2017 and other syntaxes cannot be translated. Besides, some modern browsers support ES2015 + better and better. Sometimes not all syntaxes need to be translated. So Babel has introduced a new configuration, which is the. Babelrc configuration. ‘env’ this configuration can specify the least compatible browser we expect to translate, such as the latest two versions of the browser and IE8 or later, and also supports es2015+ syntax. Plugins are simply plugins that introduce plugins. In this case, a transform-Runtime plugin was introduced, whose purpose will be discussed at the end of this article.
3.6 Continue to configure plugins.
1) Since it is a multi-page project, all our HTML pages need to be created by the front end. In order to avoid these useless repeated operations, I introduced the HTML-webpack-plugin, the code is as follows:
const entry = require('./entry');
let configPlugins = [];
// Generate pages from the entry js array
Object.keys(entry).forEach((item) = > {
config = {
filename: '.. /dist/html/' + item + '.html'.template: path.resolve(__dirname, '.. /src/index.html'),
chunks: [item]
}
configPlugins.push(new HtmlWebpackPlugin(config));
})Copy the code
First, we need to introduce the entry path array, because the usage of htML-webpack-plugin is to generate a page once instantiated, so we loop through the entry key. In each loop, config is generated based on the key information. We then instantiate the HtmlWebpackPlugin plug-in so that we can generate the HTML directories and pages we want from entry
Extract -text-webpack-plugin to extract CSS file and generate CSS file
new ExtractTextPlugin({
filename: 'css/[name].css'
})Copy the code
This configuration generates the corresponding structure and CSS file in the CSS based on the directory structure and file name of the entry, [name] also depends on pathName
3) After generating CSS files, I also expected to be able to extract common CSS and JS, so I introduced CommonsChunkPlugin, which provides the ability to extract and generate files from the common parts of chunk. The configuration is as follows:
new webpack.optimize.CommonsChunkPlugin({
name: 'reset'.filename: 'vendor/common.js'.minChunks: 3
})Copy the code
The first name attribute determines the name of the extracted public CSS file. The reset.css file is generated in the CSS directory. The second filename attribute determines the directory and name of the public JS. The common.js will be generated in the vendor directory and the third minChunks will determine how many entry files contain the module that will be extracted. I set it to 3, which means that this part will be extracted only if at least three entry JS have the same part. The CommonsChunkPlugin only provides the ability to extract public parts and generate files, but does not provide the ability to automatically generate public files in HTML pages, so we need to import public files in template files by default.
4) hot update function is essential for any developer, webpack. HotModuleReplacementPlugin plugin provides this ability, however, before using this plugin, we need to install a webpack dev – server plugin. A combination of two plug-ins is required to implement this hot update functionality.
5) The clean-webpack-plugin is also necessary to remove the specified directory and all files in it before each compilation is complete, which helps ensure that the generated code is up to date each time. The configuration code is as follows:
new CleanWebpackPlugin(['dist'] and {root: path.resolve(__dirname, '.. / ')})Copy the code
3.7 The code for the Resolve configuration is as follows:
resolve: {
extensions: ['.js'.'.vue'.'.less'].alias: {
less$: path.resolve(__dirname, 'src/assets/less'),
components$: path.resolve(__dirname, 'src/components')}}Copy the code
Alias is used to set the alias of some path, so that when importing other files, you can use this alias to replace the long path ps: Path. resolve is used to ensure that all modules import the same address. After all, the structure of the project has different levels, so that modules of different structures import different paths.
3.8 After configuring the plug-in, configure DevServer. This configuration must install the webpack-dev-server plug-in, which is also very simple to configure, the code is as follows:
var path = require('path');
module.exports = {
contentBase: path.resolve(__dirname, '.. /dist'),
host: 'we.cli'.// Don't forget to configure host
port: 8001./ / port 8001
inline: true.// Can monitor js changes
hot: true./ / hot start
compress: true.watchContentBase: false
};Copy the code
3.9 The above configuration is for the development environment, we also need to configure for the production environment, for example, compress the code, create a new webpack.config.js, and then copy the content of webpack.config.dev.js.
1) Compression of CSS is relatively easy, just add a minimum parameter to the end of each CSS-loader, as follows:
{
test: /\.less$/.exclude: /node_modules/.use: ExtractTextPlugin.extract(['css-loader? minimize'.'less-loader'])}Copy the code
2) compression js compression of js depends on webpack. Optimize the UglifyJsPlugin plug-in, we’ll plugins. Js plug-in copy a copy, rename the plugins. Prod. Js, Then introduce the webpack. Optimize. UglifyJsPlugin plug-ins, the configuration is as follows:
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false}})Copy the code
The HtmlWebpackPlugin already has this capability. Add a minify configuration as follows:
Object.keys(entry).forEach((item) = > {
config = {
filename: '.. /dist/html/' + item + '.html'.template: path.resolve(__dirname, '.. /src/index.html'),
chunks: [item],
minify: {
// Remove comments from HTML
removeComments: true.// Remove whitespace and newline characters
collapseWhitespace: true
}
}
configPlugins.push(new HtmlWebpackPlugin(config));
})Copy the code
Well, once you’ve gone through these steps, the project is built. Clone code can be run on Github, address: github.com/FedWithMori…
Third, summary
1. Why are presets a collection of plug-ins?
From the Babel website you can see that babel-Preset – ES2015 is a set of these plug-ins: transform-es2015-arrow-functions transform-es2015-block-scoped-functions transform-es2015-block-scoping transform-es2015-classes transform-es2015-computed-properties transform-es2015-constants transform-es2015-destructuring transform-es2015-for-of transform-es2015-function-name transform-es2015-literals transform-es2015-modules-commonjs transform-es2015-object-super transform-es2015-parameters transform-es2015-shorthand-properties transform-es2015-spread transform-es2015-sticky-regex transform-es2015-template-literals transform-es2015-typeof-symbol Transform-es2015 -Unicode-regex transform-Regenerator This lets us know that it is not necessary to introduce babel-ES2015, you can preset a separate translation configuration for a particular new feature
2. What does transform-Runtime do?
The answer can be under reference segmentfault.com/q/101000000… The babel-Runtime utility functions are used by default during compilation, thus reducing the amount of compiled code
Overall, this is a fairly basic configuration of Vue + Webpack, and there will be further improvements, including packaged caching for fixed third party dependencies, code checking, etc
Main references:
Webpack Documentation: doc.webpack-china.org/concepts/ Webpack Loader: doc.webpack-china.org/loaders/ Webpack Plug-in: Doc.webpack-china.org/plugins/ Babel presets and plugins configuration parsing: excaliburhan.com/post/babel-… Vue-loader:vue-loader.vuejs.org/zh-cn/start…
Finally quietly hit a small advertisement, welcome to the front of the interest of friends to join QQ group: 474471759