What is Snowpack?
Take a look at the official website:
Snowpack is a lightning-fast frontend build tool, designed for the modern web. It is an alternative to heavier, more complex bundlers like webpack or Parcel in your development workflow. Snowpack leverages JavaScript’s native module system (known as ESM) to avoid unnecessary work and stay fast no matter how big your project grows.
Once you try it, it’s impossible to go back to anything else.
Snowpack is a lightning-fast front-end build tool designed for the modern Web. It is an alternative to heavier, more complex packagers such as Webpack or Parcel in the development workflow. Snowpack leverages JavaScript’s native module system (called ESM) to avoid unnecessary work and stay fast no matter how big your project is.
Once you’ve tried it, it’s impossible to go back to anything else.
Snowpack: Fast!
In this paper, the target
- Build react project based on Snowpack, including routing, UI and other functions;
- Extensions to projects such as typescript, less, ESLint, stylelint, prettier;
- Configuration around the project, such as environment variables, path aliases, package paths, and so on.
\
Create the Snowpack project
Initialize the
Create the Snowpack project with the following command.
npx create-snowpack-app react-snowpack --template @snowpack/app-template-minimal
Copy the code
You can run the following two commands to access the directory and start the system.
cd react-snowpack
npm run start
Copy the code
After running, you can see the project Snowpack started.
Open this project and you’ll find it’s empty. Don’t worry, let’s add React to it.
React’s first page
Run the following command to install.
npm install react react-dom react-router-dom --save
Copy the code
Place the React logo under SRC/Assets /images.
Create a folder SRC under the root directory. Inside SRC, create app. JSX. This will be our first page. App. JSX will look like this.
import React, { useState, useEffect } from "react"; import logo from "./assets/images/logo.png"; import "./App.css"; function App() { const [count, setCount] = useState(0); useEffect(() => { const timer = setTimeout(() => setCount(count + 1), 1000); return () => clearTimeout(timer); }, [count, setCount]); return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1>Hello snowpack! </h1> <p> Page has been open for <code>{count}</code> seconds. </p> </header> </div> ); } export default App;Copy the code
Create SRC/app.css and add the following:
.App { text-align: center; }.App p {margin: 0.4rem; } .App-logo { height: 40vmin; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); }}Copy the code
Open the index.html file and add an empty
<div id="root"></div>
Copy the code
Js file in the root directory and create index.jsx to render the React Dom.
import React from "react";
import ReactDOM from "react-dom";
import APP from "./src/App";
ReactDOM.render(
<React.StrictMode>
<APP />
</React.StrictMode>,
document.getElementById("root")
);
Copy the code
After waiting for the page to refresh automatically, you can see the first page we created.
Add the routing
Routing is essential in a single-page project, so let’s add routing.
Respectively created SRC/pages/hello/index. The JSX files and SRC/pages/snowpack/index. The JSX file, as routing jump test page. As follows:
// hello/index.jsx import React from "react"; function Hello() { return <div className="App">I'm Hello, How are u? </div>; } export default Hello;Copy the code
// snowpack/index.jsx import React from "react"; function Snowpack() { return <div className="App">I'm Snowpack, I'm fine thank you, and you? </div>; } export default Snowpack;Copy the code
Move app.jsx and app.css to SRC /home and change the file name, app.jsx -> index.jsx, app.css -> index.css, and change the component name of index.jsx to home.
Recreate app.jsx under SRC to place the route content.
import React from "react";
import { HashRouter, Switch, Route } from "react-router-dom";
import Index from "./pages/home/index.jsx";
import Hello from "./pages/hello/index.jsx";
import Snowpack from "./pages/snowpack/index.jsx";
function App() {
return (
<div className="index">
<HashRouter>
<Switch>
<Route exact path="/" component={Index} />
<Route exact path="/hello" component={Hello} />
<Route exact path="/snowpack" component={Snowpack} />
</Switch>
</HashRouter>
</div>
);
}
Copy the code
Add a route forward in the pages/home/index directory.
import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import logo from '.. /.. /assets/images/logo.svg'; import './index.css'; function Home() { const [count, setCount] = useState(0); useEffect(() => { const timer = setTimeout(() => setCount(count + 1), 1000); return () => clearTimeout(timer); }, [count, setCount]); return ( <div className="App"> <header className="App-header"> <nav> <ul> <li> <Link to="/hello">hello</Link> </li> <li> <Link to="/snowpack">snowpack</Link> </li> </ul> </nav> <img src={logo} className="App-logo" alt="logo" /> <h1>Hello snowpack! </h1> <p> Page has been open for <code>{count}</code> seconds. </p> </header> </div> ); } export default Home;Copy the code
Now there is a jump link in the page, click the link to realize the jump!
Jump effect:
Antd
Install the following packages, @ant-Design/ICONS for antD Icon dependency libraries and dayjs for ANTD internal component dependency libraries.
npm install antd @ant-design/icons dayjs --save
Copy the code
Then import “antd/dist/antd.css” in app.jsx; When you need CSS, you can use the related components directly.
Engineering configuration
With the basic project in place, let’s start engineering the configuration.
Less
Install less.
npm install less --save-dev
Copy the code
Install snowpack-plugin-less so that Snowpack can recognize less and convert it to CSS.
npm install snowpack-plugin-less --save-dev
Copy the code
Then add the snowpack-plugin-less plugin to snowpack.config.mjs.
// snowpack.config.mjs
export default {
plugins: ['snowpack-plugin-less']
}
Copy the code
Eslint
Install eslint.
npm install eslint --save-dev
Copy the code
After installing the ESLint package, run esLint –init, as shown below for my installation options.
The.eslintrc file is automatically created in the project after installation. If you use hooks, you need to install the eslint-plugin-react-hooks package to implement hooks rules for ESLint.
The following is the recommended configuration:
module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'standard',
'prettier',
],
env: {
browser: true,
commonjs: true,
es6: true
},
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
modules: true
},
sourceType: 'module',
ecmaVersion: 6
},
plugins: ['react', '@typescript-eslint'],
settings: {
'import/ignore': ['node_modules'],
react: {
version: 'latest'
}
},
rules: {
quotes: [2, 'single'],
'no-console': 0,
'no-debugger': 1,
'no-var': 1,
semi: ['error', 'always'],
'no-irregular-whitespace': 0,
'no-trailing-spaces': 1,
'eol-last': 0,
'no-unused-vars': [
1,
{
vars: 'all',
args: 'after-used'
}
],
'no-prototype-builtins': 0,
'no-case-declarations': 0,
'no-underscore-dangle': 0,
'no-alert': 2,
'no-lone-blocks': 0,
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-delete-var': 2,
'no-dupe-keys': 2,
'use-isnan': 2,
'no-duplicate-case': 2,
'no-dupe-args': 2,
'no-empty': 2,
'no-func-assign': 2,
'no-invalid-this': 0,
'no-redeclare': 2,
'no-spaced-func': 2,
'no-this-before-super': 0,
'no-undef': 2,
'no-return-assign': 0,
'no-script-url': 2,
'no-use-before-define': 0,
'no-extra-boolean-cast': 0,
'no-unreachable': 1,
'comma-dangle': 2,
'no-mixed-spaces-and-tabs': 2,
'prefer-arrow-callback': 0,
'arrow-parens': 0,
'arrow-spacing': 0,
camelcase: 0,
'jsx-quotes': [1, 'prefer-double'],
'react/display-name': 0,
'react/forbid-prop-types': [
2,
{
forbid: ['any']
}
],
'react/jsx-boolean-value': 0,
'react/jsx-closing-bracket-location': 1,
'react/jsx-curly-spacing': [
2,
{
when: 'never',
children: true
}
],
'react/jsx-indent': ['error', 4],
'react/jsx-key': 2,
'react/jsx-no-bind': 0,
'react/jsx-no-duplicate-props': 2,
'react/jsx-no-literals': 0,
'react/jsx-no-undef': 1,
'react/jsx-pascal-case': 0,
'react/jsx-sort-props': 0,
'react/jsx-uses-react': 1,
'react/jsx-uses-vars': 2,
'react/no-danger': 0,
'react/no-did-mount-set-state': 0,
'react/no-did-update-set-state': 0,
'react/no-direct-mutation-state': 2,
'react/no-multi-comp': 0,
'react/no-set-state': 0,
'react/no-unknown-property': 2,
'react/prefer-es6-class': 2,
'react/prop-types': 0,
'react/react-in-jsx-scope': 0,
'react/self-closing-comp': 0,
'react/sort-comp': 0,
'react/no-array-index-key': 0,
'react/no-deprecated': 1,
'react/jsx-equals-spacing': 2
}
};
Copy the code
After the successful configuration, many files have become red, is it possible that some students have made obsessive-compulsive disorder, want to manually modify these problems? Don’t worry, we’ll install Prettier later to format code with one click.
Stylelint
Eslint also has a natural stylelint. Eslint checks js code formatting, while stylelint checks CSS code formatting.
Install the Stylelint-related package first, and then create stylelint.config.js in your project to store the stylelint-related rules.
npm install stylelint stylelint-config-standard --save-dev
echo {}> stylelint.config.js
Copy the code
The following is the recommended configuration:
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
ignoreFiles: [
'**/*.ts',
'**/*.tsx',
'**/*.png',
'**/*.jpg',
'**/*.jpeg',
'**/*.gif',
'**/*.mp3',
'**/*.json'
],
rules: {
'at-rule-no-unknown': [
true,
{
ignoreAtRules: ['extends', 'ignores']
}
],
indentation: 4,
'number-leading-zero': null,
'unit-allowed-list': ['em', 'rem', 's', 'px', 'deg', 'all', 'vh', 'vw', '%'],
'no-eol-whitespace': [
true,
{
ignore: 'empty-lines'
}
],
'declaration-block-trailing-semicolon': 'always',
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['global']
}
],
'block-closing-brace-newline-after': 'always',
'declaration-block-semicolon-newline-after': 'always',
'no-descending-specificity': null,
'selector-list-comma-newline-after': 'always',
'selector-pseudo-element-colon-notation': 'single'
}
};
Copy the code
Prettier
Next comes Prettier, a must-have for every front-end development, because instead of formatting code manually, it helps prettier format code with one click.
Install the prettier,
npm install prettier --save-dev
Copy the code
Because esLint is used in the project, install eslint-config-Prettier so that ESLint can work with Prettier by turning off esLint rules that contradict Prettier.
Then use echo {}> prettier. Config. js to create the prettier configuration file.
The following is the recommended configuration:
Module.exports = {// Max 100 characters printWidth: 100, // use 4 Spaces to indent tabWidth: 4, // use useTabs instead of indentation: False, // A semicolon should be used at the end of the line, // singleQuote: true, // The key of the object should be quoted only when necessary: 'as-needed', // JSX uses double quotes instead of single quotes, // trailingComma: 'None ', // braces need spacing at the beginning and end of bracketSpacing: true, // JSX tag Angle brackets need newline jsxBracketSameLine: False, // arrowParens: 'avoid', // Each file is formatted to the full contents of the file rangeStart: 0, rangeEnd: // @prettier requirePragma: false does not automatically insert @prettier insertPragma: False, / / use the default fold line standard proseWrap: 'preserve, / / according to display style decided to don't fold line htmlWhitespaceSensitivity HTML: 'CSS ', // use lf endOfLine: 'lf'};Copy the code
Then run the following command from the command line to format the entire file.
npx prettier --write .
Copy the code
Prettier-code formatter if you want to save format in vscode with one click, install the prettier-code formatter plug-in and modify the vscode configuration according to the tutorial.
Typescript
Install typescript and react and react-dom type definitions with the following command.
npm install typescript --save-dev
npm install @types/react --save-dev
npm install @types/react-dom --save-dev
npm install @typescript-eslint/eslint-plugin --save-dev
npm install @typescript-eslint/parser --save-dev
Copy the code
If you need package detection at compile time, you also need to install the following packages.
npm install @snowpack/plugin-typescript --save-dev
Copy the code
And configure it in plugins in snowpack.config.mjs:
// snowpack.config.mjs
export default {
plugins: ['@snowpack/plugin-typescript']
}
Copy the code
Create tsconfig.json and configure it by echo {}> tsconfig.json.
The following is the recommended configuration:
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ESNext",
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"outDir": "./dist/",
"esModuleInterop": true,
"noImplicitAny": false,
"sourceMap": true,
"module": "esnext",
"moduleResolution": "node",
"isolatedModules": true,
"importHelpers": true,
"lib": ["esnext", "dom", "dom.iterable"],
"skipLibCheck": false,
"jsx": "react",
"baseUrl": "./src",
"paths": {
"@src/*": ["*"],
"@assets/*": ["assets/*"],
"@components/*": ["components/*"],
"@pages/*": ["pages/*"],
"@utils/*": ["utils/*"],
"@servers/*": ["servers/*"],
"@actions/*": ["actions/*"],
"@config": ["config"],
"@routeConfig": ["routeConfig"],
"@request": ["request"]
}
},
"include": ["./src/**/*", "./declaration.d.ts"],
"exclude": ["node_modules"]
}
Copy the code
In tsconfig.json, paths are the aliases supported by TS. In addition to tsconfig.json, paths need to be configured in snowpack.config. MJS so that snowpack can be converted into corresponding paths. For project configuration, see snowpack.config. MJS Related Configuration – Path Alias Configuration section.
pre-commit
Install HusKY and List-staged.
npm install husky -save-dev
npm install lint-staged -save-dev
Copy the code
Add some configuration to package.json.
"scripts": { ... , "lint:jsx": "eslint --ext .jsx,.js src", "lint:css": "stylelint --aei .less .css src", "precommit": "lint-staged", "precommit-msg": "echo 'Pre-commit checks... ' && exit 0" }, "husky": { "hooks": { "pre-commit": "npm run lint-staged" } }, "lint-staged": { "*.{js,jsx,ts,tsx}": [ "eslint --fix", "prettier --write" ], "*.{css,less}": [ "stylelint --fix", "prettier --write" ] }Copy the code
Snowpack.config. MJS related configuration
Package path configuration
First of all, we will organize the project’s public resources file. In general, we will put the project’s index.html and index.css as static resources under /public. As shown below:
After moving, make sure to change the import path of CSS and JS in index.html.
After following the steps above, the basic structure and content of the project have been configured. Now let’s run NPM run build from the command line to see how the packaged file structure looks.
When you expand build, you can see that the files in public are packed into the build/public file, but normally you would expect index.html to be in the build root. You can mount public to the build root directory using the following configuration.
// snowpack.config.mjs
export default {
mount: {
public: '/',
}
}
Copy the code
Besides, the packaged files are not only our business code, but also the configuration code of the project, such as package.json, perttier.config.js, readme.md, etc. This code is unnecessary and takes up a small amount of space. You can package only files in the SRC directory with the following configuration Settings.
// snowpack.config.mjs
export default {
mount: {
src: '/src',
}
}
Copy the code
Package the output directory configuration
// snowpack.config.mjs
export default {
out: 'dist'
};
Copy the code
Path Alias Configuration
Alias allows you to configure path abbreviations and imported aliases for Node packages.
// snowpack.config. MJS export default {alias: {// Type 1: node package import alias lodash: 'lodash-es', // Type 2: Local file into the alias' @ SRC ':'. / SRC ', '@ assets' :'. / SRC/assets', '@ components' :'. / SRC/components', '@ pages: './src/pages', '@utils': './src/utils/', '@servers': './src/servers', '@actions': './src/actions', '@config': './src/config.ts', '@routeConfig': './src/routeConfig.tsx', '@request': './src/request.ts' }, };Copy the code
Packaging environment differentiation
Usually when we package, we want to distinguish the environment of the package by packaging command. The first step is to add the environment values to the corresponding script commands in the scripts configuration of package.json.
"scripts": {
"start": "NODE_ENV=development snowpack dev",
"build:test": "NODE_ENV=test snowpack build",
"build:prod": "NODE_ENV=production snowpack build",
},
Copy the code
If you need to obtain the environment from snowpack.config. MJS, you can obtain it directly from process.env.node_env as follows:
// snowpack.config.mjs export default { plugins: (() => { const plugin = ['snowpack-plugin-less']; if (process.env.NODE_ENV === 'development') { plugin.push('@snowpack/plugin-typescript'); } return plugin; }}) (),Copy the code
NODE_ENV in import.meta. Env, as follows:
const { NODE_ENV } = import.meta.env;
Copy the code
Setting global variables
We also need to set some built-in global variables to be used by HTML and js files, such as snowpack.config. MJS env configuration:
// snowpack.config.mjs
export default {
env: {
ENVIRONMENT: 'test'
},
}
Copy the code
Import. Meta. Env: import.
const { ENVIRONMENT } = import.meta.env;
Copy the code
In HTML, you can use %ENVIRONMENT% directly:
<script>
console.log('%ENVIRONMENT%');
</script>
Copy the code
In DevTools, you can see that part changed to the following.
Questions & Precautions
- Snowpack runtime Uncaught ReferenceError: Require is not defined.
The error was reported because Snowpack only supports ESM standard code and cannot parse CommonJS.
- snowpack Unable to resolve
cnpm
Install the package, so after the installation of the package startup error, or found that the package does not take effect, you can deletenode_modules
withnpm
或yarn
The installation. - NPM start error
[18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "fs" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "url" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "https" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "child_process" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "url" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "fs" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "http" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "http" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "https" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] /Users/huxiaomiao/pivos/react-snowpack3/node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js Module "child_process" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] url? commonjs-external Module "url" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] https? commonjs-external Module "https" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] http? commonjs-external Module "http" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] fs? commonjs-external Module "fs" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [esinstall:xmlhttprequest-ssl] child_process? commonjs-external Module "child_process" (Node.js built-in) is not available in the browser. Run Snowpack with --polyfill-node to fix. [18:30:15] [snowpack] Install failed for xmlhttprequest-ssl.Copy the code
Solution:
www.snowpack.dev/reference/c…
The last
After these, a basic project framework is basically completed, friends go to practice, welcome to discuss any questions in the comments section.
Here is my simple project framework, want to experience friends can directly clone down to play oh ~
Github.com/mogiihu/sno…