导出故事书包中的单个组件
Exporting Individual Components in storybook bundle
所以我在开发者辞职后继承了一个小故事书库,而我的 webpack/storybook 不是我的强项。
问题是配置 Storybook 构建以输出可导出组件有多容易。我想将我的 Storybook 组件(不是组件的故事,而是底层组件本身)变成一个私有的 npm 包,这样我就可以将它们导出到其他项目中。
我的故事书是@storybook react 3.2.11 运行 typescript / scss
我的文件结构如下所示...
src
components
Button
Button.tsx
button.scss
Dropdown
..etc
stories
components
Buttonstory
ButtonStory.tsx
index.tsx
我的config.js看起来像这样...
import { configure } from '@storybook/react';
function loadStories() {
require('../src/stories/index.tsx');
// You can require as many stories as you need.
}
configure(loadStories, module);
我的 .storybook webpack。config.js 看起来像这样。
const path = require("path");
const autoprefixer = require("autoprefixer");
const genDefaultConfig =
require('@storybook/react/dist/server/config/defaults/webpack.config.js');
const stylelint = require('stylelint');
const stylelintPlugin = require("stylelint-webpack-plugin");
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
// Reset rules
config.module.rules = [];
/**
* Typescript handling
* Allows webpack to process ts and tsx files using the typescript compiler.
*/
config.module.rules.push({
test: /\.(tsx?)$/,
enforce: "pre",
loader: require.resolve("tslint-loader")
});
config.module.rules.push({
test: /\.(tsx?)$/,
loader: require.resolve('awesome-typescript-loader')
});
config.resolve.extensions.push('.ts', '.tsx');
/**
* Style handling
*
* There are four loaders for handling the styling import process their hierachy is as follows:
*
* sass-loader -> postcss -> css-loader -> style-loader
*/
config.module.rules.push({
test: /\.(scss)$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 2
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: true,
plugins: function plugins() {
return [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'],
flexbox: 'no-2009'
})
]
}
}
},
{
loader: require.resolve('sass-loader'),
options: {
sourceMap: true
}
},
]
})
/**
* Begin storybook defaults
* These are the storybook defaults that we have not written over. Pretty much everything except
* styling loader and imports.
*/
config.module.rules = config.module.rules.concat([
{
test: /\.json$/,
loader: require.resolve('json-loader')
},
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: require.resolve('file-loader'),
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: require.resolve('url-loader'),
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]);
/**
* Add stylelint as a plugin, doing this because you need this to run before postCSS and as of the
* of this writing I couldn't be bothered reconfiguring postCSS to process the SCSS.
*/
config.plugins.push(new stylelintPlugin({
files: "**/*.scss",
emitErrors: false,
failOnError: false
}));
return config;
};
想知道是否有人设置过类似的东西
根据要求的评论我很久以前就解决了这个问题,不得不学习一些 webpack 但基本上最终的结果是我现在有一个
故事书 -> 私人 npm 存储库 -> 其他项目管道。
这是我解决它的方法。
.故事书
.webpack.config.js是这个.
const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');
const productionBuild = require("./webpack.prod");
const developmentBuild = require("./webpack.dev");
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
console.log(env);
config.module.rules = [];
if(env === "PRODUCTION") return productionBuild(config);
if(env === "DEVELOPMENT") return developmentBuild(config);
return config;
};
这会检查开发或生产版本,然后通过适当的文件运行它。 (我只展示制作)
const ExtractTextPlugin = require("extract-text-webpack-plugin");
// const DashboardPlugin = require('webpack-dashboard/plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const autoprefixer = require("autoprefixer");
const { TsConfigPathsPlugin } = require('awesome-typescript-loader');
module.exports = function(config) {
config.entry = {}; // remove this line if you want storybook js files in output.
config.entry["Components"] = ['./src/main.tsx'];
config.output = {
filename: 'dist/[name].bundle.js',
publicPath: '',
libraryTarget: "commonjs"
};
+
config.module.rules.push({
test: /\.(tsx?)$/,
enforce: "pre",
loader: require.resolve("tslint-loader")
});
config.plugins.push(new TsConfigPathsPlugin())
config.module.rules.push({
test: /\.(tsx?)$/,
loader: require.resolve('awesome-typescript-loader'),
options: {
configFileName: 'tsconfig.prod.json'
}
});
config.module.rules.push({
test: /\.(scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
url: false,
minimize: true,
sourceMap: false
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: false,
plugins: function plugins() {
return [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'],
flexbox: 'no-2009'
})
]
}
}
},
{
loader: require.resolve('sass-loader'),
options: {
sourceMap: false
}
},
]
})
});
config.module.rules = config.module.rules.concat([
{
test: /\.json$/,
loader: require.resolve('json-loader')
},
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: require.resolve('file-loader'),
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: require.resolve('url-loader'),
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]);
config.resolve.extensions.push('.ts', '.tsx');
config.externals = {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom'
}
};
config.plugins.push(new UglifyJSPlugin());
config.plugins.push(new ExtractTextPlugin({
filename: '[name].css',
disable: false,
allChunks: true
}));
/* unneccessary logic below is to stop webpack dashboard stalling the production build */
// config.plugins.push({
// apply: function() {
// const dashboard = new DashboardPlugin({color: "cyan"});
// dashboard.apply.apply(dashboard, arguments)
// }
// }
// );
return config;
};
^ 上面的代码是.storybook -> webpack.prod.js
基本上它所做的是覆盖故事书默认使用的 webpack 的入口点,如果你想要故事书资产,我建议你推送到 config.entry 而不是覆盖它。
webpack 所做的是遍历依赖关系树,因此 Main.tsx 是一个单独的文件,仅包含我要导出的组件,因此我的包不会膨胀。
最后有一些小的优化来减少包的大小
(1) - Tree Shaking 以移除未使用的导出
(2) - ExtractTextPlugin 获取单独的 CSS 文件
(3) - config.externals React 和 ReactDOM 这意味着输出包将不包含 React 或 ReactDOM,而是会在您导入的项目中查找那些库<<<<(重要)
下面是Main.tsx(webpack入口点)
export { BEMHelper } from "./utils/bem-helper/bem-helper";
export { Button } from "./components/Button/Button";
export { Checkbox } from "./components/Checkbox/Checkbox";
...etc etc etc repeat for every component you want to export in your bundle
import "./styles/bootstrap.scss";
最后,如果你在 typescript 配置中使用 commonJS,这将是你的 index.js(你的 NPM 包需要什么)
export const BEMHelper = require("./storybook-static/dist/Components.bundle").BEMHelper;
export const Button = require('./storybook-static/dist/Components.bundle').Button;
..... etc etc etc. (repeat)
所以我在开发者辞职后继承了一个小故事书库,而我的 webpack/storybook 不是我的强项。
问题是配置 Storybook 构建以输出可导出组件有多容易。我想将我的 Storybook 组件(不是组件的故事,而是底层组件本身)变成一个私有的 npm 包,这样我就可以将它们导出到其他项目中。
我的故事书是@storybook react 3.2.11 运行 typescript / scss 我的文件结构如下所示...
src
components
Button
Button.tsx
button.scss
Dropdown
..etc
stories
components
Buttonstory
ButtonStory.tsx
index.tsx
我的config.js看起来像这样...
import { configure } from '@storybook/react';
function loadStories() {
require('../src/stories/index.tsx');
// You can require as many stories as you need.
}
configure(loadStories, module);
我的 .storybook webpack。config.js 看起来像这样。
const path = require("path");
const autoprefixer = require("autoprefixer");
const genDefaultConfig =
require('@storybook/react/dist/server/config/defaults/webpack.config.js');
const stylelint = require('stylelint');
const stylelintPlugin = require("stylelint-webpack-plugin");
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
// Reset rules
config.module.rules = [];
/**
* Typescript handling
* Allows webpack to process ts and tsx files using the typescript compiler.
*/
config.module.rules.push({
test: /\.(tsx?)$/,
enforce: "pre",
loader: require.resolve("tslint-loader")
});
config.module.rules.push({
test: /\.(tsx?)$/,
loader: require.resolve('awesome-typescript-loader')
});
config.resolve.extensions.push('.ts', '.tsx');
/**
* Style handling
*
* There are four loaders for handling the styling import process their hierachy is as follows:
*
* sass-loader -> postcss -> css-loader -> style-loader
*/
config.module.rules.push({
test: /\.(scss)$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 2
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: true,
plugins: function plugins() {
return [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'],
flexbox: 'no-2009'
})
]
}
}
},
{
loader: require.resolve('sass-loader'),
options: {
sourceMap: true
}
},
]
})
/**
* Begin storybook defaults
* These are the storybook defaults that we have not written over. Pretty much everything except
* styling loader and imports.
*/
config.module.rules = config.module.rules.concat([
{
test: /\.json$/,
loader: require.resolve('json-loader')
},
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: require.resolve('file-loader'),
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: require.resolve('url-loader'),
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]);
/**
* Add stylelint as a plugin, doing this because you need this to run before postCSS and as of the
* of this writing I couldn't be bothered reconfiguring postCSS to process the SCSS.
*/
config.plugins.push(new stylelintPlugin({
files: "**/*.scss",
emitErrors: false,
failOnError: false
}));
return config;
};
想知道是否有人设置过类似的东西
根据要求的评论我很久以前就解决了这个问题,不得不学习一些 webpack 但基本上最终的结果是我现在有一个 故事书 -> 私人 npm 存储库 -> 其他项目管道。 这是我解决它的方法。
.故事书 .webpack.config.js是这个.
const genDefaultConfig = require('@storybook/react/dist/server/config/defaults/webpack.config.js');
const productionBuild = require("./webpack.prod");
const developmentBuild = require("./webpack.dev");
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig, env);
console.log(env);
config.module.rules = [];
if(env === "PRODUCTION") return productionBuild(config);
if(env === "DEVELOPMENT") return developmentBuild(config);
return config;
};
这会检查开发或生产版本,然后通过适当的文件运行它。 (我只展示制作)
const ExtractTextPlugin = require("extract-text-webpack-plugin");
// const DashboardPlugin = require('webpack-dashboard/plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const autoprefixer = require("autoprefixer");
const { TsConfigPathsPlugin } = require('awesome-typescript-loader');
module.exports = function(config) {
config.entry = {}; // remove this line if you want storybook js files in output.
config.entry["Components"] = ['./src/main.tsx'];
config.output = {
filename: 'dist/[name].bundle.js',
publicPath: '',
libraryTarget: "commonjs"
};
+
config.module.rules.push({
test: /\.(tsx?)$/,
enforce: "pre",
loader: require.resolve("tslint-loader")
});
config.plugins.push(new TsConfigPathsPlugin())
config.module.rules.push({
test: /\.(tsx?)$/,
loader: require.resolve('awesome-typescript-loader'),
options: {
configFileName: 'tsconfig.prod.json'
}
});
config.module.rules.push({
test: /\.(scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
url: false,
minimize: true,
sourceMap: false
}
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: false,
plugins: function plugins() {
return [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'],
flexbox: 'no-2009'
})
]
}
}
},
{
loader: require.resolve('sass-loader'),
options: {
sourceMap: false
}
},
]
})
});
config.module.rules = config.module.rules.concat([
{
test: /\.json$/,
loader: require.resolve('json-loader')
},
{
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: require.resolve('file-loader'),
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
loader: require.resolve('url-loader'),
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]);
config.resolve.extensions.push('.ts', '.tsx');
config.externals = {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom'
}
};
config.plugins.push(new UglifyJSPlugin());
config.plugins.push(new ExtractTextPlugin({
filename: '[name].css',
disable: false,
allChunks: true
}));
/* unneccessary logic below is to stop webpack dashboard stalling the production build */
// config.plugins.push({
// apply: function() {
// const dashboard = new DashboardPlugin({color: "cyan"});
// dashboard.apply.apply(dashboard, arguments)
// }
// }
// );
return config;
};
^ 上面的代码是.storybook -> webpack.prod.js 基本上它所做的是覆盖故事书默认使用的 webpack 的入口点,如果你想要故事书资产,我建议你推送到 config.entry 而不是覆盖它。
webpack 所做的是遍历依赖关系树,因此 Main.tsx 是一个单独的文件,仅包含我要导出的组件,因此我的包不会膨胀。
最后有一些小的优化来减少包的大小 (1) - Tree Shaking 以移除未使用的导出 (2) - ExtractTextPlugin 获取单独的 CSS 文件 (3) - config.externals React 和 ReactDOM 这意味着输出包将不包含 React 或 ReactDOM,而是会在您导入的项目中查找那些库<<<<(重要)
下面是Main.tsx(webpack入口点)
export { BEMHelper } from "./utils/bem-helper/bem-helper";
export { Button } from "./components/Button/Button";
export { Checkbox } from "./components/Checkbox/Checkbox";
...etc etc etc repeat for every component you want to export in your bundle
import "./styles/bootstrap.scss";
最后,如果你在 typescript 配置中使用 commonJS,这将是你的 index.js(你的 NPM 包需要什么)
export const BEMHelper = require("./storybook-static/dist/Components.bundle").BEMHelper;
export const Button = require('./storybook-static/dist/Components.bundle').Button;
..... etc etc etc. (repeat)