Since I started to use ES6
liberally, I became quite addicted to it, and many of the projects I handled gradually transformed into single-page projects based on react.js
. I took a lot of detours along the way, especially regarding the selection and use of various tools. After messing around for half a year, I’m jotting down some things I used during this process and some pitfalls I encountered.
Before starting, let’s briefly introduce some knowledge about npm. Since modern projects rely on various tool plugins, a package management tool is needed to address script and package installation issues. npm, as the module dependency management tool of Node.js, can handle these problems quite well.
To start a project, first run the command below in the project directory
$ npm init
npm will ask you a series of questions, including project name, version, description, etc. You can fill them out in detail or simply keep hitting enter. Once completed, a file named package.json
will be generated in the current directory, a simple example is as follows:
{
"name": "temp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"css-loader": "^0.25.0",
"style-loader": "^0.13.1"
},
"devDependencies": {
"dufing": "^1.0.13"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"fn": "echo \"123\""
},
"author": "",
"license": "ISC"
}
Among them, the fields name
, version
, and description
represent the project name, version, and description, respectively, while main
indicates the main entry file of the project.
The dependencies
and devDependencies
are what we often focus on, describing the files that the project depends on. If we install the corresponding dependencies in the project and also want this dependency to be recorded in package.json
, we can execute the following command:
# css-loader will be recorded in dependencies
$ npm install css-loader --save
# dufing will be recorded in devDependencies
$ npm install dufing --save-dev
In this way, when someone gets a new project, as long as there is package.json
present, running
$ npm install
will automatically install the dependencies in dependencies
and devDependencies
.
Some may ask what the difference is between dependencies
and devDependencies
? You can simply understand the former as the dependencies necessary for the project to run, while the latter refers to the plugins needed for development. If you run npm install
with the --production
flag, the system will only install the files in dependencies
.
The scripts
field records various scripts, which can be executed using npm run [name]
. For example, executing npm run fn
on the aforementioned package.json
will output 123 in the console. Although scripts
might seem simple, if used well, it can even replace automation tools like gulp. Since this is not the focus of this discussion, I won’t elaborate further.
When it comes to front-end automation tools, grunt
( grunt official website , grunt Chinese website ) and gulp
( gulp official website , gulp Chinese website ) are well-known. Both excel at handling front-end automation tasks. The difference is that grunt is a pioneer in front-end engineering, leaning towards configuration, which might make it easier for those from other languages to pick up. Gulp is more modern, less configuration-heavy, and adopts a streaming method to process tasks, making it more efficient.
As for whether to use grunt or gulp, it depends on your actual situation. But for me:
I am an early grunt user, now a gulp user, and will be an npm script user in the future.
The reason for mentioning npm script
is that gulp
and grunt
have certain limitations; although you can usually find suitable plugins, sometimes you may not find the plugin you want (what to do? Unless you write it yourself) and debugging difficulties might arise. In many cases, you still need to install gulp or grunt, but npm script
is different; most projects will have a package.json
, and based on this configuration file, we can easily run npm scripts. More importantly, its functionality is much more powerful than we imagine. Since npm script
is not the focus of this discussion, I won't elaborate further, just providing two links for those interested: [ You Might Not Need Gulp, Grunt? , Use npm scripts instead of gulp ].
Gulp mainly handles the automatic execution of various front-end tasks, such as automatic compilation of sass, bundling of es6, compilation of react, compression of js, version control of static files, etc.
Installing gulp is straightforward: first, install gulp-cli
$ npm install --global gulp-cli
Then, install gulp in the project directory
$ npm install --save-dev gulp
Create a gulp configuration file named gulpfile.js
in the project directory. Specific content can be seen on the official website (or refer to the configuration in the example below).
Finally, run gulp in the project directory
$ gulp
Now, let's briefly illustrate with a real project (since this mainly describes the entire development process, I will skip steps like js compression and static file version control and emphasize some important parts).
The project directory is as follows:
├── dist
│ ├── css
│ ├── fonts
│ ├── images
│ ├── index.html
│ └── js
├── gulpfile.js
├── package.json
└── src
├── fonts // Static resources
├── images // Static resources
├── index.jsx // Main entry for react project
├── jsx // Other functional modules of the react project
├── js // Static resources
└── sass // Sass directory
/src
is the development directory, containing some directories for static files (fonts, images, js, etc.)/src/jsx
is the directory for the project's necessary react.js files/src/sass
is the corresponding directory for sass files/src/index.jsx
is the main entry for this project /dist
is the output directory for the project; all files processed will be placed in this directory. Since all file resources will be packed into this directory, if there are any operations related to deployment, just take this directory online.In fact, this project involves doing several things:
Thus, this project has three main tasks:
webpack
task processes es6 and react compilation using gulp-webpack
;sass
task processes the compilation of sass resources using gulp-sass
;static
task processes copying static resources, etc.Let’s take a look at the contents of gulpfile.js
:
// Import necessary resources
const gulp = require('gulp');
const webpack = require('gulp-webpack'); // gulp-webpack is used for es6 and jsx processing
const sass = require('gulp-sass'); // gulp-sass is used for processing sass -> css
// Webpack task, which will be detailed later, skipped here
gulp.task('webpack', function () {
return gulp.src('src/**/*.jsx')
.pipe(webpack({
watch: true,
entry: {
index: './src/index.jsx'
},
output: {
filename: './js/[name].js',
chunkFilename: './js/[name].chunk.js',
},
module: {
loaders: [{
test: /.jsx?$/,
loader: 'babel-loader',
query: {
compact: false,
presets: ['es2015', 'react']
}
}, {
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}]
}
}))
.pipe(gulp.dest('dist/'));
});
/**
* Sass task
* Compile all .scss files under /src/sass and place the compiled files into /dist/css
**/
gulp.task('sass', function () {
return gulp.src('./src/sass/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./dist/css'));
});
/**
* Static task
* Responsible mainly for placing static files into the /dist/* directory
**/
gulp.task('static', function () {
gulp.src('./src/fonts/**/*.*')
.pipe(gulp.dest('./dist/fonts'));
gulp.src('./src/images/**/*.*')
.pipe(gulp.dest('./dist/images'));
gulp.src('./src/page/**/*.*')
.pipe(gulp.dest('./dist'));
});
/**
* Pack webpac, sass, and static tasks,
* so when executing gulp, webpack, sass, and static tasks will be executed automatically.
*/
gulp.task('default', ['webpack', 'sass', 'static'], function () {});
// Monitor the corresponding directories, so that when files are modified, gulp will automatically execute the corresponding tasks
gulp.watch('src/sass/**/*.scss', ['sass']);
gulp.watch('src/fonts/**/*.*', ['static']);
gulp.watch('src/images/**/*.*', ['static']);
gulp.watch('index.html', ['static']);
With the official release of ECMAScript 2015 (formerly known as ECMAScript 6 or ES6, hereafter referred to as ES6) in June 2015, browser support for ES6 has been increasing. Some developers have shifted from small-scale to large-scale use, even making it a standard for new projects.
After using ES6 on a large scale for some time, I happened to discover that there are some people around me who think that some browsers currently do not support ES6, so it’s still too early to understand ES6. In fact, these compatibility issues already have mature solutions, the most famous being babel. I won’t delve into the usage of babel here; you can refer to some explanations on the official website.
Here we will use Webpack to handle the modularity and bundling of front-end resources. So what is Webpack used for? Quoting a phrase from the Webpack Chinese Guide:
Webpack is currently the most popular tool for front-end resource modular management and bundling. It can package many loose modules according to dependencies and rules into front-end resources suitable for production environment deployment. It can also perform code splitting for on-demand loading modules and load them asynchronously when actually needed. Through loader transformations, any form of resource can be regarded as a module, such as CommonJs modules, AMD modules, ES6 modules, CSS, images, JSON, Coffeescript, LESS, etc.
Here we use Webpack to handle ES6, ES6 module loading, and Reactjs compilation, as follows:
First, install webpack
$ npm install webpack -g
Then install it in the project directory
$ npm install webpack --save-dev
At this point, you can use the webpack command to bundle files. For example, we have two files as follows:
// index.js
console.log('hello');
var m = require('./moudle.js');
m();
// moudle.js
module.exports = function(){
console.log('world')
}
Here index.js is the entry file, and moudle.js is its dependent module. In index, we introduced the content of module.js.
Next, start compiling by executing the following command:
// Use index.js as the entry to bundle into bundle.js
$ webpack index.js bundle.js
The command line will print out the following information and produce a file named bundle.js, which is the successfully bundled final file.
Hash: 9f99cbe53612bf1056ab
Version: webpack 2.1.0-beta.25
Time: 62ms
Asset Size Chunks Chunk Names
bundle.js 2.62 kB 0 [emitted] main
[0] ./moudle.js 53 bytes {0} [built]
[1] ./index.js 59 bytes {0} [built]
At this point, if you include bundle.js in an HTML file and open it in the browser, you can see the output of hello and world in the console.
Loaders can be considered one of the most magical aspects of webpack, allowing it to handle other types of files. You can require any supported type of modules or files, such as jsx, less, sass, images, etc.
Let’s start with a simple example.
In the previous directory, we can create a new css file
/* style.css */
body { background: red; }
Then modify index.js
// index.js
require('!style!css!./style.css') // Use style and css loaders to process the css file
console.log('hello');
var m = require('./moudle.js');
m();
Install the loaders:
$ npm install css-loader style-loader
Recompile
$ webpack index.js bundle.js
After compiling the bundle.js, include it in the HTML file and open it, and you will find the page's background turns red.
Careful readers may ask if writing require('!style!css!./style.css')
this way means writing !style!css!
every time would be inconvenient. In fact, we can also write the loader in the compilation script:
$ webpack entry.js bundle.js --module-bind "css=style!css"
Or write it in the webpack configuration, in which case we can simply write the following when importing the corresponding file.
require("./style.css")
Under normal circumstances, we can create a webpack.config.js
file in the root directory of the project and write various configurations in it. A simple example is as follows:
// webpack.config.js
// Import webpack
var webpack = require('webpack')
module.exports = {
entry: './index.js', // Entry file for the project
output: {
filename: 'bundle.js' // Output file
},
module: {
loaders: [
{test: /\.css$/, loader: 'style!css'} // Loader being used
]
}
}
With the configuration in place, we can directly execute the following script in the project directory, and webpack will follow the configuration’s agreement:
$ webpack
Likewise in Gulp, we can continue to use the webpack config file, or we can write webpack configurations in Gulp. Here’s how to use webpack in Gulp to handle es6 and react.
Let’s go straight to the code, which is detailed in the comments. Before executing, you might need to install the packages below:
# Gulp dependencies for babel and sass
$ npm install gulp-babel gulp-sass node-sass --save-dev
# Babel dependencies
$ npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev
# Sass and css dependencies
$ npm install css-loader style-loader sass-loader --save-dev
Specific configuration:
// See context code in 1.2's gulpfile.js, here only introducing the webpack task
gulp.task('webpack', function () {
// Handle all .jsx files under src
return gulp.src('src/**/*.jsx')
.pipe(webpack({
watch: true,
entry: {
index: './src/index.jsx'
// Entry file is src/index.js
},
output: {
filename: './js/[name].js',
// Output file to the js/ directory, filename is jsx file prefix + js
chunkFilename: './js/[name].chunk.js',
// If using require, files in require will be packed into a separate file.
},
module: {
loaders: [{
test: /.jsx?$/,
loader: 'babel-loader',
// Using babel-loader to process jsx files
query: {
compact: false,
presets: ['es2015', 'react']
// Process es2015 and react files
}
}, {
test: /\.scss$/,
loaders: ["style", "css", "sass"]
// Process sass
}]
}
}))
.pipe(gulp.dest('dist/'));
// Compiled files go to the dist directory
});
Sass is an extension of CSS that makes the CSS language more powerful and elegant. It allows you to use variables, nested rules, mixins, imports, and many more features while fully compatible with CSS syntax. Sass helps keep large stylesheets well-structured while allowing you to quickly start small projects, especially when used in conjunction with the Compass style library.
Similar to Sass, there’s also lesscss. As for which is easier to use, that’s subjective, and I won’t delve into that here.
Sass is based on Ruby, so it must be installed properly before starting. Most Mac systems come with Ruby pre-installed, so you don’t need to worry about that. But Windows users will need to install it themselves ( install Ruby ).
Once Ruby is installed, we can install Sass with a single command (due to certain well-known reasons, you may not be able to access Ruby's mirror sites; here you can use Taobao's Ruby mirror):
$ gem install sass
Once installed, you can execute sass -v
to check the version of sass. If a file needs to be compiled, you can use the command below:
$ sass test.scss:test.css test1.scss:test1.css --watch
The above command means to compile test.scss into test.css and test1.scss into test1.css. The --watch command is used for monitoring; if the file changes, Sass will compile CSS automatically.
I won’t go into the syntax of Sass here; you can refer to the following resources:
While I previously explained how to use the command line to compile Sass files, in most cases, we cannot list all Sass files one by one. This is where tools like Gulp can come in handy.
Let's take an example:
Before starting, you might need to install the appropriate package:
$ npm install gulp-sass --save-dev
Note: If you only use gulp-sass
and don’t execute Sass via the command line, you don’t need to install Sass from section 3.1.
// gulpfile.js
// For complete configuration, see the previous text; here only the configuration of the Sass-related task is introduced.
// Import sass
const sass = require('gulp-sass');
// Sass task
gulp.task('sass', function () {
// Add all .scss files in the src/sass directory to the task
return gulp.src('./src/sass/**/*.scss')
// Compile .scss files with sass
.pipe(sass().on('error', sass.logError))
// Place compiled files in the dist/css directory
.pipe(gulp.dest('./dist/css'));
});
React, as a new generation library for building user interfaces, has become widely popular. I originally planned to detail the usage of React, but later found that a good Chinese documentation suffices. In the future, when I have time, I’ll share some insights on handling data flow with React and my experiences during its usage.
Related resources:
The above is some experience of Mofei using React in actual work; purely personal exploration, and some places may not be the optimal solution. If you have any suggestions or corrections, please feel free to share for mutual improvement.